* Re: [PATCH] powerpc/32s: Don't flush all TLBs when flushing one page
From: Christophe Leroy @ 2020-02-01 14:53 UTC (permalink / raw)
To: Segher Boessenkool; +Cc: Paul Mackerras, linuxppc-dev, linux-kernel
In-Reply-To: <20200201140629.GM22482@gate.crashing.org>
Le 01/02/2020 à 15:06, Segher Boessenkool a écrit :
> On Sat, Feb 01, 2020 at 08:27:03AM +0100, Christophe Leroy wrote:
>> Le 31/01/2020 à 20:38, Segher Boessenkool a écrit :
>>> On Fri, Jan 31, 2020 at 05:15:20PM +0100, Christophe Leroy wrote:
>>>> Le 31/01/2020 à 16:51, Segher Boessenkool a écrit :
>>>>> On Fri, Jan 31, 2020 at 03:37:34PM +0000, Christophe Leroy wrote:
>>>>>> When the range is a single page, do a page flush instead.
>>>>>
>>>>>> + start &= PAGE_MASK;
>>>>>> + end = (end - 1) | ~PAGE_MASK;
>>>>>> if (!Hash) {
>>>>>> - _tlbia();
>>>>>> + if (end - start == PAGE_SIZE)
>>>>>> + _tlbie(start);
>>>>>> + else
>>>>>> + _tlbia();
>>>>>> return;
>>>>>> }
>>>>>
>>>>> For just one page, you get end - start == 0 actually?
>>>>
>>>> Oops, good catch.
>>>>
>>>> Indeed you don't get PAGE_SIZE but (PAGE_SIZE - 1) for just one page.
>>>
>>> You have all low bits masked off in both start and end, so you get zero.
>>> You could make the condion read "if (start == end)?
>>
>> No, in end the low bits are set, that's a BIT OR with ~PAGE_MASK, so it
>> sets all low bits to 1.
>
> Oh, wow, yes, I cannot read apparently.
>
> Maybe there are some ROUND_DOWN and ROUND_UP macros you could use?
>
Yes but my intention was to modify the existing code as less as possible.
What do you think about version v2 of the patch ?
Christophe
^ permalink raw reply
* Re: [PATCH] powerpc/32s: Don't flush all TLBs when flushing one page
From: Segher Boessenkool @ 2020-02-01 14:06 UTC (permalink / raw)
To: Christophe Leroy; +Cc: Paul Mackerras, linuxppc-dev, linux-kernel
In-Reply-To: <248a3cf3-1b5e-a6e1-ceec-0e3904d1cf51@c-s.fr>
On Sat, Feb 01, 2020 at 08:27:03AM +0100, Christophe Leroy wrote:
> Le 31/01/2020 à 20:38, Segher Boessenkool a écrit :
> >On Fri, Jan 31, 2020 at 05:15:20PM +0100, Christophe Leroy wrote:
> >>Le 31/01/2020 à 16:51, Segher Boessenkool a écrit :
> >>>On Fri, Jan 31, 2020 at 03:37:34PM +0000, Christophe Leroy wrote:
> >>>>When the range is a single page, do a page flush instead.
> >>>
> >>>>+ start &= PAGE_MASK;
> >>>>+ end = (end - 1) | ~PAGE_MASK;
> >>>> if (!Hash) {
> >>>>- _tlbia();
> >>>>+ if (end - start == PAGE_SIZE)
> >>>>+ _tlbie(start);
> >>>>+ else
> >>>>+ _tlbia();
> >>>> return;
> >>>> }
> >>>
> >>>For just one page, you get end - start == 0 actually?
> >>
> >>Oops, good catch.
> >>
> >>Indeed you don't get PAGE_SIZE but (PAGE_SIZE - 1) for just one page.
> >
> >You have all low bits masked off in both start and end, so you get zero.
> >You could make the condion read "if (start == end)?
>
> No, in end the low bits are set, that's a BIT OR with ~PAGE_MASK, so it
> sets all low bits to 1.
Oh, wow, yes, I cannot read apparently.
Maybe there are some ROUND_DOWN and ROUND_UP macros you could use?
Segher
^ permalink raw reply
* [PATCH v2] powerpc/32s: Don't flush all TLBs when flushing one page
From: Christophe Leroy @ 2020-02-01 8:04 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
When flushing any memory range, the flushing function
flushes all TLBs.
When (start) and (end - 1) are in the same memory page,
flush that page instead.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
v2: Reworked the test as the previous one was always false (end - start was PAGE_SIZE - 1 for a single page)
---
arch/powerpc/mm/book3s32/tlb.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/mm/book3s32/tlb.c b/arch/powerpc/mm/book3s32/tlb.c
index 2fcd321040ff..724c0490fb17 100644
--- a/arch/powerpc/mm/book3s32/tlb.c
+++ b/arch/powerpc/mm/book3s32/tlb.c
@@ -79,11 +79,14 @@ static void flush_range(struct mm_struct *mm, unsigned long start,
int count;
unsigned int ctx = mm->context.id;
+ start &= PAGE_MASK;
if (!Hash) {
- _tlbia();
+ if (end - start <= PAGE_SIZE)
+ _tlbie(start);
+ else
+ _tlbia();
return;
}
- start &= PAGE_MASK;
if (start >= end)
return;
end = (end - 1) | ~PAGE_MASK;
--
2.25.0
^ permalink raw reply related
* Re: [PATCH] powerpc/32s: Don't flush all TLBs when flushing one page
From: Christophe Leroy @ 2020-02-01 7:27 UTC (permalink / raw)
To: Segher Boessenkool; +Cc: Paul Mackerras, linuxppc-dev, linux-kernel
In-Reply-To: <20200131193833.GF22482@gate.crashing.org>
Le 31/01/2020 à 20:38, Segher Boessenkool a écrit :
> On Fri, Jan 31, 2020 at 05:15:20PM +0100, Christophe Leroy wrote:
>> Le 31/01/2020 à 16:51, Segher Boessenkool a écrit :
>>> On Fri, Jan 31, 2020 at 03:37:34PM +0000, Christophe Leroy wrote:
>>>> When the range is a single page, do a page flush instead.
>>>
>>>> + start &= PAGE_MASK;
>>>> + end = (end - 1) | ~PAGE_MASK;
>>>> if (!Hash) {
>>>> - _tlbia();
>>>> + if (end - start == PAGE_SIZE)
>>>> + _tlbie(start);
>>>> + else
>>>> + _tlbia();
>>>> return;
>>>> }
>>>
>>> For just one page, you get end - start == 0 actually?
>>
>> Oops, good catch.
>>
>> Indeed you don't get PAGE_SIZE but (PAGE_SIZE - 1) for just one page.
>
> You have all low bits masked off in both start and end, so you get zero.
> You could make the condion read "if (start == end)?
No, in end the low bits are set, that's a BIT OR with ~PAGE_MASK, so it
sets all low bits to 1.
Christophe
^ permalink raw reply
* Re: [PATCH] drivers: char: hvc: add arm JTAG DCC console support
From: reinaldo rojas @ 2020-02-01 5:06 UTC (permalink / raw)
To: linuxppc-dev@lists.ozlabs.org
Enviado desde mi iPad
^ permalink raw reply
* Re: [PATCH] powerpc/32s: Don't flush all TLBs when flushing one page
From: Segher Boessenkool @ 2020-01-31 19:38 UTC (permalink / raw)
To: Christophe Leroy; +Cc: Paul Mackerras, linuxppc-dev, linux-kernel
In-Reply-To: <27cef66b-df5b-0baa-abac-5532e58bd055@c-s.fr>
On Fri, Jan 31, 2020 at 05:15:20PM +0100, Christophe Leroy wrote:
> Le 31/01/2020 à 16:51, Segher Boessenkool a écrit :
> >On Fri, Jan 31, 2020 at 03:37:34PM +0000, Christophe Leroy wrote:
> >>When the range is a single page, do a page flush instead.
> >
> >>+ start &= PAGE_MASK;
> >>+ end = (end - 1) | ~PAGE_MASK;
> >> if (!Hash) {
> >>- _tlbia();
> >>+ if (end - start == PAGE_SIZE)
> >>+ _tlbie(start);
> >>+ else
> >>+ _tlbia();
> >> return;
> >> }
> >
> >For just one page, you get end - start == 0 actually?
>
> Oops, good catch.
>
> Indeed you don't get PAGE_SIZE but (PAGE_SIZE - 1) for just one page.
You have all low bits masked off in both start and end, so you get zero.
You could make the condion read "if (start == end)?
Maybe a nicer way to describe what you do is "if start and end are on the
same memory page, flush that page."
Segher
^ permalink raw reply
* Re: [PATCH] powerpc/32s: Don't flush all TLBs when flushing one page
From: Christophe Leroy @ 2020-01-31 16:15 UTC (permalink / raw)
To: Segher Boessenkool; +Cc: Paul Mackerras, linuxppc-dev, linux-kernel
In-Reply-To: <20200131155150.GD22482@gate.crashing.org>
Le 31/01/2020 à 16:51, Segher Boessenkool a écrit :
> On Fri, Jan 31, 2020 at 03:37:34PM +0000, Christophe Leroy wrote:
>> When the range is a single page, do a page flush instead.
>
>> + start &= PAGE_MASK;
>> + end = (end - 1) | ~PAGE_MASK;
>> if (!Hash) {
>> - _tlbia();
>> + if (end - start == PAGE_SIZE)
>> + _tlbie(start);
>> + else
>> + _tlbia();
>> return;
>> }
>
> For just one page, you get end - start == 0 actually?
>
>
Oops, good catch.
Indeed you don't get PAGE_SIZE but (PAGE_SIZE - 1) for just one page.
Christophe
^ permalink raw reply
* Re: [PATCH] powerpc/32s: Don't flush all TLBs when flushing one page
From: Segher Boessenkool @ 2020-01-31 15:51 UTC (permalink / raw)
To: Christophe Leroy; +Cc: Paul Mackerras, linuxppc-dev, linux-kernel
In-Reply-To: <e31c57eb5308a5a73a5c8232454c0dd9f65f6175.1580485014.git.christophe.leroy@c-s.fr>
On Fri, Jan 31, 2020 at 03:37:34PM +0000, Christophe Leroy wrote:
> When the range is a single page, do a page flush instead.
> + start &= PAGE_MASK;
> + end = (end - 1) | ~PAGE_MASK;
> if (!Hash) {
> - _tlbia();
> + if (end - start == PAGE_SIZE)
> + _tlbie(start);
> + else
> + _tlbia();
> return;
> }
For just one page, you get end - start == 0 actually?
Segher
^ permalink raw reply
* [PATCH] powerpc/32s: Don't flush all TLBs when flushing one page
From: Christophe Leroy @ 2020-01-31 15:37 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
When flushing a range, the flushing function flushes all TLBs.
When the range is a single page, do a page flush instead.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/mm/book3s32/tlb.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/mm/book3s32/tlb.c b/arch/powerpc/mm/book3s32/tlb.c
index 2fcd321040ff..8e0089065a7e 100644
--- a/arch/powerpc/mm/book3s32/tlb.c
+++ b/arch/powerpc/mm/book3s32/tlb.c
@@ -79,14 +79,17 @@ static void flush_range(struct mm_struct *mm, unsigned long start,
int count;
unsigned int ctx = mm->context.id;
+ start &= PAGE_MASK;
+ end = (end - 1) | ~PAGE_MASK;
if (!Hash) {
- _tlbia();
+ if (end - start == PAGE_SIZE)
+ _tlbie(start);
+ else
+ _tlbia();
return;
}
- start &= PAGE_MASK;
if (start >= end)
return;
- end = (end - 1) | ~PAGE_MASK;
pmd = pmd_offset(pud_offset(pgd_offset(mm, start), start), start);
for (;;) {
pmd_end = ((start + PGDIR_SIZE) & PGDIR_MASK) - 1;
--
2.25.0
^ permalink raw reply related
* [PATCH] powerpc/nohash: Don't flush all TLBs when flushing one page
From: Christophe Leroy @ 2020-01-31 15:37 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
When flushing a range, the flushing function flushes all TLBs.
When the range is a single page, do a page flush instead.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/mm/nohash/tlb.c | 27 +++++++++++++++++++++++----
1 file changed, 23 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/mm/nohash/tlb.c b/arch/powerpc/mm/nohash/tlb.c
index 696f568253a0..3d05d70c54dc 100644
--- a/arch/powerpc/mm/nohash/tlb.c
+++ b/arch/powerpc/mm/nohash/tlb.c
@@ -362,13 +362,32 @@ void __init early_init_mmu_47x(void)
*/
void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
+ int tsize = mmu_get_tsize(mmu_virtual_psize);
+
#ifdef CONFIG_SMP
preempt_disable();
- smp_call_function(do_flush_tlb_mm_ipi, NULL, 1);
- _tlbil_pid(0);
+#endif
+ start = ALIGN_DOWN(start, PAGE_SIZE);
+ end = ALIGN(end, PAGE_SIZE);
+ if (end - start == PAGE_SIZE) {
+#ifdef CONFIG_SMP
+ struct tlb_flush_param p = {
+ .pid = 0,
+ .addr = start,
+ .tsize = tsize,
+ .ind = 0,
+ };
+ smp_call_function(do_flush_tlb_page_ipi, &p, 1);
+#endif
+ _tlbil_va(start, 0, tsize, 0);
+ } else {
+#ifdef CONFIG_SMP
+ smp_call_function(do_flush_tlb_mm_ipi, NULL, 1);
+#endif
+ _tlbil_pid(0);
+ }
+#ifdef CONFIG_SMP
preempt_enable();
-#else
- _tlbil_pid(0);
#endif
}
EXPORT_SYMBOL(flush_tlb_kernel_range);
--
2.25.0
^ permalink raw reply related
* [PATCH v2 7/7] powerpc/32: use set_memory_attr()
From: Christophe Leroy @ 2020-01-31 13:34 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <84be5ad6a996adf5693260749dcb4d8c69182073.1580477672.git.christophe.leroy@c-s.fr>
Use set_memory_attr() instead of the PPC32 specific change_page_attr()
change_page_attr() was checking that the address was not mapped by
blocks and was handling highmem, but that's unneeded because the
affected pages can't be in highmem and block mapping verification
is already done by the callers.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
v2: new
---
arch/powerpc/mm/pgtable_32.c | 95 ++++--------------------------------
1 file changed, 10 insertions(+), 85 deletions(-)
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 5fb90edd865e..3d92eaf3ee2f 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -23,6 +23,7 @@
#include <linux/highmem.h>
#include <linux/memblock.h>
#include <linux/slab.h>
+#include <linux/set_memory.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -121,99 +122,20 @@ void __init mapin_ram(void)
}
}
-/* Scan the real Linux page tables and return a PTE pointer for
- * a virtual address in a context.
- * Returns true (1) if PTE was found, zero otherwise. The pointer to
- * the PTE pointer is unmodified if PTE is not found.
- */
-static int
-get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp)
-{
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
- int retval = 0;
-
- pgd = pgd_offset(mm, addr & PAGE_MASK);
- if (pgd) {
- pud = pud_offset(pgd, addr & PAGE_MASK);
- if (pud && pud_present(*pud)) {
- pmd = pmd_offset(pud, addr & PAGE_MASK);
- if (pmd_present(*pmd)) {
- pte = pte_offset_map(pmd, addr & PAGE_MASK);
- if (pte) {
- retval = 1;
- *ptep = pte;
- if (pmdp)
- *pmdp = pmd;
- /* XXX caller needs to do pte_unmap, yuck */
- }
- }
- }
- }
- return(retval);
-}
-
-static int __change_page_attr_noflush(struct page *page, pgprot_t prot)
-{
- pte_t *kpte;
- pmd_t *kpmd;
- unsigned long address;
-
- BUG_ON(PageHighMem(page));
- address = (unsigned long)page_address(page);
-
- if (v_block_mapped(address))
- return 0;
- if (!get_pteptr(&init_mm, address, &kpte, &kpmd))
- return -EINVAL;
- __set_pte_at(&init_mm, address, kpte, mk_pte(page, prot), 0);
- pte_unmap(kpte);
-
- return 0;
-}
-
-/*
- * Change the page attributes of an page in the linear mapping.
- *
- * THIS DOES NOTHING WITH BAT MAPPINGS, DEBUG USE ONLY
- */
-static int change_page_attr(struct page *page, int numpages, pgprot_t prot)
-{
- int i, err = 0;
- unsigned long flags;
- struct page *start = page;
-
- local_irq_save(flags);
- for (i = 0; i < numpages; i++, page++) {
- err = __change_page_attr_noflush(page, prot);
- if (err)
- break;
- }
- wmb();
- local_irq_restore(flags);
- flush_tlb_kernel_range((unsigned long)page_address(start),
- (unsigned long)page_address(page));
- return err;
-}
-
void mark_initmem_nx(void)
{
- struct page *page = virt_to_page(_sinittext);
unsigned long numpages = PFN_UP((unsigned long)_einittext) -
PFN_DOWN((unsigned long)_sinittext);
if (v_block_mapped((unsigned long)_stext + 1))
mmu_mark_initmem_nx();
else
- change_page_attr(page, numpages, PAGE_KERNEL);
+ set_memory_attr((unsigned long)_sinittext, numpages, PAGE_KERNEL);
}
#ifdef CONFIG_STRICT_KERNEL_RWX
void mark_rodata_ro(void)
{
- struct page *page;
unsigned long numpages;
if (v_block_mapped((unsigned long)_sinittext)) {
@@ -222,20 +144,18 @@ void mark_rodata_ro(void)
return;
}
- page = virt_to_page(_stext);
numpages = PFN_UP((unsigned long)_etext) -
PFN_DOWN((unsigned long)_stext);
- change_page_attr(page, numpages, PAGE_KERNEL_ROX);
+ set_memory_attr((unsigned long)_stext, numpages, PAGE_KERNEL_ROX);
/*
* mark .rodata as read only. Use __init_begin rather than __end_rodata
* to cover NOTES and EXCEPTION_TABLE.
*/
- page = virt_to_page(__start_rodata);
numpages = PFN_UP((unsigned long)__init_begin) -
PFN_DOWN((unsigned long)__start_rodata);
- change_page_attr(page, numpages, PAGE_KERNEL_RO);
+ set_memory_attr((unsigned long)__start_rodata, numpages, PAGE_KERNEL_RO);
// mark_initmem_nx() should have already run by now
ptdump_check_wx();
@@ -245,9 +165,14 @@ void mark_rodata_ro(void)
#ifdef CONFIG_DEBUG_PAGEALLOC
void __kernel_map_pages(struct page *page, int numpages, int enable)
{
+ unsigned long addr = (unsigned long)page_address(page);
+
if (PageHighMem(page))
return;
- change_page_attr(page, numpages, enable ? PAGE_KERNEL : __pgprot(0));
+ if (enable)
+ set_memory_attr(addr, numpages, PAGE_KERNEL);
+ else
+ set_memory_attr(addr, numpages, __pgprot(0));
}
#endif /* CONFIG_DEBUG_PAGEALLOC */
--
2.25.0
^ permalink raw reply related
* [PATCH v2 6/7] powerpc/mm: implement set_memory_attr()
From: Christophe Leroy @ 2020-01-31 13:34 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <84be5ad6a996adf5693260749dcb4d8c69182073.1580477672.git.christophe.leroy@c-s.fr>
In addition to the set_memory_xx() functions which allows to change
the memory attributes of not (yet) used memory regions, implement a
set_memory_attr() function to:
- set the final memory protection after init on currently used
kernel regions.
- enable/disable kernel memory regions in the scope of DEBUG_PAGEALLOC.
Unlike the set_memory_xx() which can act in three step as the regions
are unused, this function must modify 'on the fly' as the kernel is
executing from them. At the moment only PPC32 will use it and changing
page attributes on the fly is not an issue.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
v2: new
---
arch/powerpc/include/asm/set_memory.h | 2 ++
arch/powerpc/mm/pageattr.c | 33 +++++++++++++++++++++++++++
2 files changed, 35 insertions(+)
diff --git a/arch/powerpc/include/asm/set_memory.h b/arch/powerpc/include/asm/set_memory.h
index c3621030a3fb..4dadff67e265 100644
--- a/arch/powerpc/include/asm/set_memory.h
+++ b/arch/powerpc/include/asm/set_memory.h
@@ -29,4 +29,6 @@ static inline int set_memory_x(unsigned long addr, int numpages)
return change_memory_attr(addr, numpages, SET_MEMORY_X);
}
+int set_memory_attr(unsigned long addr, int numpages, pgprot_t prot);
+
#endif
diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c
index 0cb5294732b7..dff6c92cd09b 100644
--- a/arch/powerpc/mm/pageattr.c
+++ b/arch/powerpc/mm/pageattr.c
@@ -72,3 +72,36 @@ int change_memory_attr(unsigned long addr, int numpages, int action)
return apply_to_page_range(&init_mm, start, sz, change_page_attr, (void *)action);
}
+
+/*
+ * Set the attributes of a page:
+ *
+ * This function is used by PPC32 at the end of init to set final kernel memory
+ * protection. It includes changing the maping of the page it is executing from
+ * and data pages it is using.
+ */
+static int set_page_attr(pte_t *ptep, unsigned long addr, void *data)
+{
+ pgprot_t prot = __pgprot((int)data);
+
+ spin_lock(&init_mm.page_table_lock);
+
+ set_pte_at(&init_mm, addr, ptep, pte_modify(*ptep, prot));
+ flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+
+ spin_unlock(&init_mm.page_table_lock);
+
+ return 0;
+}
+
+int set_memory_attr(unsigned long addr, int numpages, pgprot_t prot)
+{
+ unsigned long start = ALIGN_DOWN(addr, PAGE_SIZE);
+ unsigned long sz = numpages * PAGE_SIZE;
+
+ if (!numpages)
+ return 0;
+
+ return apply_to_page_range(&init_mm, start, sz, set_page_attr,
+ (void *)pgprot_val(prot));
+}
--
2.25.0
^ permalink raw reply related
* [PATCH v2 5/7] powerpc/configs: Enable STRICT_MODULE_RWX in skiroot_defconfig
From: Christophe Leroy @ 2020-01-31 13:34 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <84be5ad6a996adf5693260749dcb4d8c69182073.1580477672.git.christophe.leroy@c-s.fr>
From: Russell Currey <ruscur@russell.cc>
skiroot_defconfig is the only powerpc defconfig with STRICT_KERNEL_RWX
enabled, and if you want memory protection for kernel text you'd want it
for modules too, so enable STRICT_MODULE_RWX there.
Acked-by: Joel Stanley <joel@joel.id.au>
Signed-off-by: Russell Currey <ruscur@russell.cc>
---
v2: no change
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/configs/skiroot_defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/powerpc/configs/skiroot_defconfig b/arch/powerpc/configs/skiroot_defconfig
index 069f67f12731..b74358c3ede8 100644
--- a/arch/powerpc/configs/skiroot_defconfig
+++ b/arch/powerpc/configs/skiroot_defconfig
@@ -31,6 +31,7 @@ CONFIG_PERF_EVENTS=y
CONFIG_SLAB_FREELIST_HARDENED=y
CONFIG_JUMP_LABEL=y
CONFIG_STRICT_KERNEL_RWX=y
+CONFIG_STRICT_MODULE_RWX=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_SIG=y
--
2.25.0
^ permalink raw reply related
* [PATCH v2 4/7] powerpc: Set ARCH_HAS_STRICT_MODULE_RWX
From: Christophe Leroy @ 2020-01-31 13:34 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <84be5ad6a996adf5693260749dcb4d8c69182073.1580477672.git.christophe.leroy@c-s.fr>
From: Russell Currey <ruscur@russell.cc>
To enable strict module RWX on powerpc, set:
CONFIG_STRICT_MODULE_RWX=y
You should also have CONFIG_STRICT_KERNEL_RWX=y set to have any real
security benefit.
ARCH_HAS_STRICT_MODULE_RWX is set to require ARCH_HAS_STRICT_KERNEL_RWX.
This is due to a quirk in arch/Kconfig and arch/powerpc/Kconfig that
makes STRICT_MODULE_RWX *on by default* in configurations where
STRICT_KERNEL_RWX is *unavailable*.
Since this doesn't make much sense, and module RWX without kernel RWX
doesn't make much sense, having the same dependencies as kernel RWX
works around this problem.
Signed-off-by: Russell Currey <ruscur@russell.cc>
---
v2: no change
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/Kconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index ae6a27d07406..371e3bef5c32 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -131,6 +131,7 @@ config PPC
select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
select ARCH_HAS_SET_MEMORY
select ARCH_HAS_STRICT_KERNEL_RWX if ((PPC_BOOK3S_64 || PPC32) && !HIBERNATION)
+ select ARCH_HAS_STRICT_MODULE_RWX if ARCH_HAS_STRICT_KERNEL_RWX
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_HAS_UACCESS_FLUSHCACHE
select ARCH_HAS_UACCESS_MCSAFE if PPC64
--
2.25.0
^ permalink raw reply related
* [PATCH v2 3/7] powerpc/mm/ptdump: debugfs handler for W+X checks at runtime
From: Christophe Leroy @ 2020-01-31 13:34 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <84be5ad6a996adf5693260749dcb4d8c69182073.1580477672.git.christophe.leroy@c-s.fr>
From: Russell Currey <ruscur@russell.cc>
Very rudimentary, just
echo 1 > [debugfs]/check_wx_pages
and check the kernel log. Useful for testing strict module RWX.
Updated the Kconfig entry to reflect this.
Also fixed a typo.
Signed-off-by: Russell Currey <ruscur@russell.cc>
---
v2: no change
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/Kconfig.debug | 6 ++++--
arch/powerpc/mm/ptdump/ptdump.c | 21 ++++++++++++++++++++-
2 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index 0b063830eea8..e37960ef68c6 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -370,7 +370,7 @@ config PPC_PTDUMP
If you are unsure, say N.
config PPC_DEBUG_WX
- bool "Warn on W+X mappings at boot"
+ bool "Warn on W+X mappings at boot & enable manual checks at runtime"
depends on PPC_PTDUMP && STRICT_KERNEL_RWX
help
Generate a warning if any W+X mappings are found at boot.
@@ -384,7 +384,9 @@ config PPC_DEBUG_WX
of other unfixed kernel bugs easier.
There is no runtime or memory usage effect of this option
- once the kernel has booted up - it's a one time check.
+ once the kernel has booted up, it only automatically checks once.
+
+ Enables the "check_wx_pages" debugfs entry for checking at runtime.
If in doubt, say "Y".
diff --git a/arch/powerpc/mm/ptdump/ptdump.c b/arch/powerpc/mm/ptdump/ptdump.c
index 206156255247..a15e19a3b14e 100644
--- a/arch/powerpc/mm/ptdump/ptdump.c
+++ b/arch/powerpc/mm/ptdump/ptdump.c
@@ -4,7 +4,7 @@
*
* This traverses the kernel pagetables and dumps the
* information about the used sections of memory to
- * /sys/kernel/debug/kernel_pagetables.
+ * /sys/kernel/debug/kernel_page_tables.
*
* Derived from the arm64 implementation:
* Copyright (c) 2014, The Linux Foundation, Laura Abbott.
@@ -413,6 +413,25 @@ void ptdump_check_wx(void)
else
pr_info("Checked W+X mappings: passed, no W+X pages found\n");
}
+
+static int check_wx_debugfs_set(void *data, u64 val)
+{
+ if (val != 1ULL)
+ return -EINVAL;
+
+ ptdump_check_wx();
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(check_wx_fops, NULL, check_wx_debugfs_set, "%llu\n");
+
+static int ptdump_check_wx_init(void)
+{
+ return debugfs_create_file("check_wx_pages", 0200, NULL,
+ NULL, &check_wx_fops) ? 0 : -ENOMEM;
+}
+device_initcall(ptdump_check_wx_init);
#endif
static int ptdump_init(void)
--
2.25.0
^ permalink raw reply related
* [PATCH v2 2/7] powerpc/kprobes: Mark newly allocated probes as RO
From: Christophe Leroy @ 2020-01-31 13:34 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <84be5ad6a996adf5693260749dcb4d8c69182073.1580477672.git.christophe.leroy@c-s.fr>
With CONFIG_STRICT_KERNEL_RWX=y and CONFIG_KPROBES=y, there will be one
W+X page at boot by default. This can be tested with
CONFIG_PPC_PTDUMP=y and CONFIG_PPC_DEBUG_WX=y set, and checking the
kernel log during boot.
powerpc doesn't implement its own alloc() for kprobes like other
architectures do, but we couldn't immediately mark RO anyway since we do
a memcpy to the page we allocate later. After that, nothing should be
allowed to modify the page, and write permissions are removed well
before the kprobe is armed.
The memcpy() would fail if >1 probes were allocated, so use
patch_instruction() instead which is safe for RO.
Reviewed-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
v2: removed the redundant flush
---
arch/powerpc/kernel/kprobes.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index 2d27ec4feee4..d3e594e6094c 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -24,6 +24,7 @@
#include <asm/sstep.h>
#include <asm/sections.h>
#include <linux/uaccess.h>
+#include <linux/set_memory.h>
DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
@@ -124,13 +125,12 @@ int arch_prepare_kprobe(struct kprobe *p)
}
if (!ret) {
- memcpy(p->ainsn.insn, p->addr,
- MAX_INSN_SIZE * sizeof(kprobe_opcode_t));
+ patch_instruction(p->ainsn.insn, *p->addr);
p->opcode = *p->addr;
- flush_icache_range((unsigned long)p->ainsn.insn,
- (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
}
+ set_memory_ro((unsigned long)p->ainsn.insn, 1);
+
p->ainsn.boostable = 0;
return ret;
}
--
2.25.0
^ permalink raw reply related
* [PATCH v2 1/7] powerpc/mm: Implement set_memory() routines
From: Christophe Leroy @ 2020-01-31 13:34 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
The set_memory_{ro/rw/nx/x}() functions are required for STRICT_MODULE_RWX,
and are generally useful primitives to have. This implementation is
designed to be completely generic across powerpc's many MMUs.
It's possible that this could be optimised to be faster for specific
MMUs, but the focus is on having a generic and safe implementation for
now.
This implementation does not handle cases where the caller is attempting
to change the mapping of the page it is executing from, or if another
CPU is concurrently using the page being altered. These cases likely
shouldn't happen, but a more complex implementation with MMU-specific code
could safely handle them, so that is left as a TODO for now.
Signed-off-by: Russell Currey <ruscur@russell.cc>
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
v2:
- use integers instead of pointers for action
- drop action check, nobody should call change_memory_attr() directly.
Should it happen, the function will just do nothing.
- Renamed confusing 'pte_val' var to 'pte' as pte_val() is already a function.
---
arch/powerpc/Kconfig | 1 +
arch/powerpc/include/asm/set_memory.h | 32 ++++++++++++
arch/powerpc/mm/Makefile | 1 +
arch/powerpc/mm/pageattr.c | 74 +++++++++++++++++++++++++++
4 files changed, 108 insertions(+)
create mode 100644 arch/powerpc/include/asm/set_memory.h
create mode 100644 arch/powerpc/mm/pageattr.c
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a8fdb36a841e..ae6a27d07406 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -129,6 +129,7 @@ config PPC
select ARCH_HAS_PTE_SPECIAL
select ARCH_HAS_MEMBARRIER_CALLBACKS
select ARCH_HAS_SCALED_CPUTIME if VIRT_CPU_ACCOUNTING_NATIVE && PPC_BOOK3S_64
+ select ARCH_HAS_SET_MEMORY
select ARCH_HAS_STRICT_KERNEL_RWX if ((PPC_BOOK3S_64 || PPC32) && !HIBERNATION)
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
select ARCH_HAS_UACCESS_FLUSHCACHE
diff --git a/arch/powerpc/include/asm/set_memory.h b/arch/powerpc/include/asm/set_memory.h
new file mode 100644
index 000000000000..c3621030a3fb
--- /dev/null
+++ b/arch/powerpc/include/asm/set_memory.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_SET_MEMORY_H
+#define _ASM_POWERPC_SET_MEMORY_H
+
+#define SET_MEMORY_RO 0
+#define SET_MEMORY_RW 1
+#define SET_MEMORY_NX 2
+#define SET_MEMORY_X 3
+
+int change_memory_attr(unsigned long addr, int numpages, int action);
+
+static inline int set_memory_ro(unsigned long addr, int numpages)
+{
+ return change_memory_attr(addr, numpages, SET_MEMORY_RO);
+}
+
+static inline int set_memory_rw(unsigned long addr, int numpages)
+{
+ return change_memory_attr(addr, numpages, SET_MEMORY_RW);
+}
+
+static inline int set_memory_nx(unsigned long addr, int numpages)
+{
+ return change_memory_attr(addr, numpages, SET_MEMORY_NX);
+}
+
+static inline int set_memory_x(unsigned long addr, int numpages)
+{
+ return change_memory_attr(addr, numpages, SET_MEMORY_X);
+}
+
+#endif
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index 5e147986400d..d0a0bcbc9289 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_PPC_COPRO_BASE) += copro_fault.o
obj-$(CONFIG_PPC_PTDUMP) += ptdump/
obj-$(CONFIG_KASAN) += kasan/
+obj-$(CONFIG_ARCH_HAS_SET_MEMORY) += pageattr.o
diff --git a/arch/powerpc/mm/pageattr.c b/arch/powerpc/mm/pageattr.c
new file mode 100644
index 000000000000..0cb5294732b7
--- /dev/null
+++ b/arch/powerpc/mm/pageattr.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * MMU-generic set_memory implementation for powerpc
+ *
+ * Copyright 2019, IBM Corporation.
+ */
+
+#include <linux/mm.h>
+#include <linux/set_memory.h>
+
+#include <asm/mmu.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+
+/*
+ * Updates the attributes of a page in three steps:
+ *
+ * 1. invalidate the page table entry
+ * 2. flush the TLB
+ * 3. install the new entry with the updated attributes
+ *
+ * This is unsafe if the caller is attempting to change the mapping of the
+ * page it is executing from, or if another CPU is concurrently using the
+ * page being altered.
+ *
+ * TODO make the implementation resistant to this.
+ */
+static int change_page_attr(pte_t *ptep, unsigned long addr, void *data)
+{
+ int action = (int)data;
+ pte_t pte;
+
+ spin_lock(&init_mm.page_table_lock);
+
+ /* invalidate the PTE so it's safe to modify */
+ pte = ptep_get_and_clear(&init_mm, addr, ptep);
+ flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+
+ /* modify the PTE bits as desired, then apply */
+ switch (action) {
+ case SET_MEMORY_RO:
+ pte = pte_wrprotect(pte);
+ break;
+ case SET_MEMORY_RW:
+ pte = pte_mkwrite(pte);
+ break;
+ case SET_MEMORY_NX:
+ pte = pte_exprotect(pte);
+ break;
+ case SET_MEMORY_X:
+ pte = pte_mkexec(pte);
+ break;
+ default:
+ break;
+ }
+
+ set_pte_at(&init_mm, addr, ptep, pte);
+ spin_unlock(&init_mm.page_table_lock);
+
+ return 0;
+}
+
+int change_memory_attr(unsigned long addr, int numpages, int action)
+{
+ unsigned long start = ALIGN_DOWN(addr, PAGE_SIZE);
+ unsigned long sz = numpages * PAGE_SIZE;
+
+ if (!numpages)
+ return 0;
+
+ return apply_to_page_range(&init_mm, start, sz, change_page_attr, (void *)action);
+}
--
2.25.0
^ permalink raw reply related
* [PATCH v2] powerpc: drmem: avoid NULL pointer dereference when drmem is unavailable
From: Michal Suchanek @ 2020-01-31 13:28 UTC (permalink / raw)
To: linuxppc-dev, Nathan Lynch, Libor Pechacek
Cc: David Hildenbrand, Michal Suchanek, stable, linux-kernel,
Paul Mackerras, Leonardo Bras, Thomas Gleixner, Michal Suchanek,
Allison Randal
In-Reply-To: <20200128101945.GA20336@fm.suse.cz>
From: Libor Pechacek <lpechacek@suse.cz>
In guests without hotplugagble memory drmem structure is only zero
initialized. Trying to manipulate DLPAR parameters results in a crash.
$ echo "memory add count 1" > /sys/kernel/dlpar
Oops: Kernel access of bad area, sig: 11 [#1]
LE PAGE_SIZE=64K MMU=Hash SMP NR_CPUS=2048 NUMA pSeries
Modules linked in: af_packet(E) rfkill(E) nvram(E) vmx_crypto(E)
gf128mul(E) e1000(E) virtio_balloon(E) rtc_generic(E) crct10dif_vpmsum(E)
btrfs(E) blake2b_generic(E) libcrc32c(E) xor(E) raid6_pq(E) virtio_rng(E)
virtio_blk(E) ohci_pci(E) ehci_pci(E) ohci_hcd(E) ehci_hcd(E)
crc32c_vpmsum(E) usbcore(E) virtio_pci(E) virtio_ring(E) virtio(E) sg(E)
dm_multipath(E) dm_mod(E) scsi_dh_rdac(E) scsi_dh_emc(E) scsi_dh_alua(E)
scsi_mod(E)
CPU: 1 PID: 4114 Comm: bash Kdump: loaded Tainted: G E 5.5.0-rc6-2-default #1
NIP: c0000000000ff294 LR: c0000000000ff248 CTR: 0000000000000000
REGS: c0000000fb9d3880 TRAP: 0300 Tainted: G E (5.5.0-rc6-2-default)
MSR: 8000000000009033 <SF,EE,ME,IR,DR,RI,LE> CR: 28242428 XER: 20000000
CFAR: c0000000009a6c10 DAR: 0000000000000010 DSISR: 40000000 IRQMASK: 0
GPR00: c0000000000ff248 c0000000fb9d3b10 c000000001682e00 0000000000000033
GPR04: c0000000ff30bf90 c0000000ff394800 0000000000005110 ffffffffffffffe8
GPR08: 0000000000000000 0000000000000000 00000000fe1c0000 0000000000000000
GPR12: 0000000000002200 c00000003fffee00 0000000000000000 000000011cbc37c0
GPR16: 000000011cb27ed0 0000000000000000 000000011cb6dd10 0000000000000000
GPR20: 000000011cb7db28 000001003ce035f0 000000011cbc7828 000000011cbc6c70
GPR24: 000001003cf01210 0000000000000000 c0000000ffade4e0 c000000002d7216b
GPR28: 0000000000000001 c000000002d78560 0000000000000000 c0000000015458d0
NIP [c0000000000ff294] dlpar_memory+0x6e4/0xd00
LR [c0000000000ff248] dlpar_memory+0x698/0xd00
Call Trace:
[c0000000fb9d3b10] [c0000000000ff248] dlpar_memory+0x698/0xd00 (unreliable)
[c0000000fb9d3ba0] [c0000000000f5990] handle_dlpar_errorlog+0xc0/0x190
[c0000000fb9d3c10] [c0000000000f5c58] dlpar_store+0x198/0x4a0
[c0000000fb9d3cd0] [c000000000c4cb00] kobj_attr_store+0x30/0x50
[c0000000fb9d3cf0] [c0000000005a37b4] sysfs_kf_write+0x64/0x90
[c0000000fb9d3d10] [c0000000005a2c90] kernfs_fop_write+0x1b0/0x290
[c0000000fb9d3d60] [c0000000004a2bec] __vfs_write+0x3c/0x70
[c0000000fb9d3d80] [c0000000004a6560] vfs_write+0xd0/0x260
[c0000000fb9d3dd0] [c0000000004a69ac] ksys_write+0xdc/0x130
[c0000000fb9d3e20] [c00000000000b478] system_call+0x5c/0x68
Instruction dump:
ebc90000 1ce70018 38e7ffe8 7cfe3a14 7fbe3840 419dff14 fb610068 7fc9f378
39000000 4800000c 60000000 4195fef4 <81490010> 39290018 38c80001 7ea93840
---[ end trace cc2dd8152608c295 ]---
Taking closer look at the code, I can see that for_each_drmem_lmb is a
macro expanding into `for (lmb = &drmem_info->lmbs[0]; lmb <=
&drmem_info->lmbs[drmem_info->n_lmbs - 1]; lmb++)`. When drmem_info->lmbs
is NULL, the loop would iterate through the whole address range if it
weren't stopped by the NULL pointer dereference on the next line.
This patch aligns for_each_drmem_lmb and for_each_drmem_lmb_in_range macro
behavior with the common C semantics, where the end marker does not belong
to the scanned range, and alters get_lmb_range() semantics. As a side
effect, the wraparound observed in the crash is prevented.
Fixes: 6c6ea53725b3 ("powerpc/mm: Separate ibm, dynamic-memory data from DT format")
Cc: Michal Suchanek <msuchanek@suse.cz>
Cc: stable@vger.kernel.org
Signed-off-by: Libor Pechacek <lpechacek@suse.cz>
Signed-off-by: Michal Suchanek <msuchanek@suse.de>
---
v2: rename last_lmb -> limit, clarify error condition.
---
arch/powerpc/include/asm/drmem.h | 4 ++--
arch/powerpc/platforms/pseries/hotplug-memory.c | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/include/asm/drmem.h b/arch/powerpc/include/asm/drmem.h
index 3d76e1c388c2..28c3d936fdf3 100644
--- a/arch/powerpc/include/asm/drmem.h
+++ b/arch/powerpc/include/asm/drmem.h
@@ -27,12 +27,12 @@ struct drmem_lmb_info {
extern struct drmem_lmb_info *drmem_info;
#define for_each_drmem_lmb_in_range(lmb, start, end) \
- for ((lmb) = (start); (lmb) <= (end); (lmb)++)
+ for ((lmb) = (start); (lmb) < (end); (lmb)++)
#define for_each_drmem_lmb(lmb) \
for_each_drmem_lmb_in_range((lmb), \
&drmem_info->lmbs[0], \
- &drmem_info->lmbs[drmem_info->n_lmbs - 1])
+ &drmem_info->lmbs[drmem_info->n_lmbs])
/*
* The of_drconf_cell_v1 struct defines the layout of the LMB data
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index c126b94d1943..a6b207dd1d7d 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -223,7 +223,7 @@ static int get_lmb_range(u32 drc_index, int n_lmbs,
struct drmem_lmb **end_lmb)
{
struct drmem_lmb *lmb, *start, *end;
- struct drmem_lmb *last_lmb;
+ struct drmem_lmb *limit;
start = NULL;
for_each_drmem_lmb(lmb) {
@@ -236,10 +236,10 @@ static int get_lmb_range(u32 drc_index, int n_lmbs,
if (!start)
return -EINVAL;
- end = &start[n_lmbs - 1];
+ end = &start[n_lmbs];
- last_lmb = &drmem_info->lmbs[drmem_info->n_lmbs - 1];
- if (end > last_lmb)
+ limit = &drmem_info->lmbs[drmem_info->n_lmbs];
+ if (end > limit)
return -EINVAL;
*start_lmb = start;
--
2.23.0
^ permalink raw reply related
* Re: powerpc Linux scv support and scv system call ABI proposal
From: Segher Boessenkool @ 2020-01-31 11:55 UTC (permalink / raw)
To: Adhemerval Zanella
Cc: Florian Weimer, libc-alpha, Tulio Magno Quites Machado Filho,
linuxppc-dev, Nicholas Piggin
In-Reply-To: <7568c170-55ef-d3b0-fe85-e5bec68c1fe1@linaro.org>
Hi!
On Fri, Jan 31, 2020 at 08:30:45AM -0300, Adhemerval Zanella wrote:
> On 30/01/2020 18:41, Segher Boessenkool wrote:
> > On Thu, Jan 30, 2020 at 02:04:51PM -0300, Adhemerval Zanella wrote:
> >> be value propagated over
> >> functions calls and over different scopes, which I take from your
> >> explanation is not supported and fragile.
> >
> > You probably misundertand that, but let me ask: where is err assigned to
> > at all in the code you quoted? I don't see it. Maybe it's hidden in some
> > macro?
>
> Indeed it was not explicit in the example code, it is burried in the
> INTERNAL_SYSCALL_CALL macro which calls sparc-defined macros. For instance,
> with 6 argument kernel syscall, it issues:
>
> #define inline_syscall6(string,err,name,arg1,arg2,arg3,arg4,arg5,arg6) \
> ({ \
> register long __o0 __asm__ ("o0") = (long)(arg1); \
> register long __o1 __asm__ ("o1") = (long)(arg2); \
> register long __o2 __asm__ ("o2") = (long)(arg3); \
> register long __o3 __asm__ ("o3") = (long)(arg4); \
> register long __o4 __asm__ ("o4") = (long)(arg5); \
> register long __o5 __asm__ ("o5") = (long)(arg6); \
> err = name; \
> __asm __volatile (string : "=r" (err), "=r" (__o0) : \
> "0" (err), "1" (__o0), "r" (__o1), \
> "r" (__o2), "r" (__o3), "r" (__o4), \
> "r" (__o5) : \
> __SYSCALL_CLOBBERS); \
> __o0; \
> })
>
> Where 'err' defined by 'INTERNAL_SYSCALL_DECL' should be the 'err' macro
> argument.
GCC makes sure that what is in register g1 at the end of this asm does
end up in the C variable "err" (at least conceptually, the actual code
can be optimised further).
> I meant a register variable where its use 'after' the extended asm
> is expected to use the define register.
Yes, that is not supported like this. You'll have to use some more
inline asm at that use (with "err" as input there). Or, if you actually
care about this being in a specific register, maybe you shouldn't write
this in C at all? Writing assembler code in assembler language (in a
single inline asm block, or even in an assembler source file) tends to
give much better results (and is a lot easier) than trying to second-
guess the compiler. You can write pretty much anything as inline
assembler code, but that doesn't mean you have to, or that that would
be a good idea.
Things on the border like system calls are hard to handle. I like the
idea of doing those in compiler builtins ("compiler intrinsics"), but
that has its own problems as well: mostly, need to {write down / lock
down / determine in advance} more of the calling convention than the
other approaches. And of course it will take years before most projects
can use it :-/
Segher
^ permalink raw reply
* [PATCH v3 2/2] powerpc: Don't user thread struct for saving SRR0/1 on syscall.
From: Christophe Leroy @ 2020-01-31 11:34 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <8ee3bdbbdfdfc64ca7001e90c43b2aee6f333578.1580470482.git.christophe.leroy@c-s.fr>
CR0 can be saved later, and CTR can also be used for saving.
Keep SRR1 in r9 and stash SRR0 in CTR, this avoids using
thread_struct in memory for that.
Saves 3 cycles (ie 1%) in null_syscall selftest on 8xx.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
v3: New
---
arch/powerpc/kernel/head_32.h | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/kernel/head_32.h b/arch/powerpc/kernel/head_32.h
index 0e7bf28fe53a..4a1faeded069 100644
--- a/arch/powerpc/kernel/head_32.h
+++ b/arch/powerpc/kernel/head_32.h
@@ -114,28 +114,23 @@
mfspr r9, SPRN_SRR1
#ifdef CONFIG_VMAP_STACK
mfspr r11, SPRN_SRR0
- stw r11, SRR0(r12)
- stw r9, SRR1(r12)
+ mtctr r11
#endif
- mfcr r10
andi. r11, r9, MSR_PR
lwz r11,TASK_STACK-THREAD(r12)
beq- 99f
- rlwinm r10,r10,0,4,2 /* Clear SO bit in CR */
addi r11, r11, THREAD_SIZE - INT_FRAME_SIZE
#ifdef CONFIG_VMAP_STACK
- li r9, MSR_KERNEL & ~(MSR_IR | MSR_RI) /* can take DTLB miss */
- mtmsr r9
+ li r10, MSR_KERNEL & ~(MSR_IR | MSR_RI) /* can take DTLB miss */
+ mtmsr r10
isync
#endif
tovirt_vmstack r12, r12
tophys_novmstack r11, r11
- stw r10,_CCR(r11) /* save registers */
mflr r10
stw r10, _LINK(r11)
#ifdef CONFIG_VMAP_STACK
- lwz r10, SRR0(r12)
- lwz r9, SRR1(r12)
+ mfctr r10
#else
mfspr r10,SPRN_SRR0
#endif
@@ -143,6 +138,9 @@
stw r1,0(r11)
tovirt_novmstack r1, r11 /* set new kernel sp */
stw r10,_NIP(r11)
+ mfcr r10
+ rlwinm r10,r10,0,4,2 /* Clear SO bit in CR */
+ stw r10,_CCR(r11) /* save registers */
#ifdef CONFIG_40x
rlwinm r9,r9,0,14,12 /* clear MSR_WE (necessary?) */
#else
--
2.25.0
^ permalink raw reply related
* [PATCH v3 1/2] powerpc/32: Warn and return ENOSYS on syscalls from kernel
From: Christophe Leroy @ 2020-01-31 11:34 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman
Cc: linuxppc-dev, linux-kernel
Since commit b86fb88855ea ("powerpc/32: implement fast entry for
syscalls on non BOOKE") and commit 1a4b739bbb4f ("powerpc/32:
implement fast entry for syscalls on BOOKE"), syscalls from
kernel are unexpected and can have catastrophic consequences
as it will destroy the kernel stack.
Test MSR_PR on syscall entry. In case syscall is from kernel,
emit a warning and return ENOSYS error.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
v2: Rebased on powerpc/next-test, ie on top of VMAP_STACK series
v3:
- Rebased on today's powerpc/merge.
- Reloading both SRR0 and SRR1 in ret_from_kernel_syscall allthough
SRR1 is already in r9 at the time being, allows more flexibility and
less prone to risk of errors for future changes in the syscall entry.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/kernel/entry_32.S | 27 +++++++++++++++++++++++++++
arch/powerpc/kernel/head_32.h | 16 +++++++++-------
arch/powerpc/kernel/head_booke.h | 5 ++++-
3 files changed, 40 insertions(+), 8 deletions(-)
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 77abbc34bbe0..e808626ff230 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -575,6 +575,33 @@ syscall_exit_work:
bl do_syscall_trace_leave
b ret_from_except_full
+ /*
+ * System call was called from kernel. We get here with SRR1 in r9.
+ * Mark the exception as recoverable once we have retrieved SRR0,
+ * trap a warning and return ENOSYS with CR[SO] set.
+ */
+ .globl ret_from_kernel_syscall
+ret_from_kernel_syscall:
+ mfspr r9, SPRN_SRR0
+ mfspr r10, SPRN_SRR1
+#if !defined(CONFIG_4xx) && !defined(CONFIG_BOOKE)
+ LOAD_REG_IMMEDIATE(r11, MSR_KERNEL & ~(MSR_IR|MSR_DR))
+ mtmsr r11
+#endif
+
+0: trap
+ EMIT_BUG_ENTRY 0b,__FILE__,__LINE__, BUGFLAG_WARNING
+
+ li r3, ENOSYS
+ crset so
+#if defined(CONFIG_PPC_8xx) && defined(CONFIG_PERF_EVENTS)
+ mtspr SPRN_NRI, r0
+#endif
+ mtspr SPRN_SRR0, r9
+ mtspr SPRN_SRR1, r10
+ SYNC
+ RFI
+
/*
* The fork/clone functions need to copy the full register set into
* the child process. Therefore we need to save all the nonvolatile
diff --git a/arch/powerpc/kernel/head_32.h b/arch/powerpc/kernel/head_32.h
index a6a5fbbf8504..0e7bf28fe53a 100644
--- a/arch/powerpc/kernel/head_32.h
+++ b/arch/powerpc/kernel/head_32.h
@@ -111,14 +111,16 @@
.macro SYSCALL_ENTRY trapno
mfspr r12,SPRN_SPRG_THREAD
+ mfspr r9, SPRN_SRR1
#ifdef CONFIG_VMAP_STACK
- mfspr r9, SPRN_SRR0
- mfspr r11, SPRN_SRR1
- stw r9, SRR0(r12)
- stw r11, SRR1(r12)
+ mfspr r11, SPRN_SRR0
+ stw r11, SRR0(r12)
+ stw r9, SRR1(r12)
#endif
mfcr r10
+ andi. r11, r9, MSR_PR
lwz r11,TASK_STACK-THREAD(r12)
+ beq- 99f
rlwinm r10,r10,0,4,2 /* Clear SO bit in CR */
addi r11, r11, THREAD_SIZE - INT_FRAME_SIZE
#ifdef CONFIG_VMAP_STACK
@@ -128,15 +130,14 @@
#endif
tovirt_vmstack r12, r12
tophys_novmstack r11, r11
- mflr r9
stw r10,_CCR(r11) /* save registers */
- stw r9, _LINK(r11)
+ mflr r10
+ stw r10, _LINK(r11)
#ifdef CONFIG_VMAP_STACK
lwz r10, SRR0(r12)
lwz r9, SRR1(r12)
#else
mfspr r10,SPRN_SRR0
- mfspr r9,SPRN_SRR1
#endif
stw r1,GPR1(r11)
stw r1,0(r11)
@@ -209,6 +210,7 @@
mtspr SPRN_SRR0,r11
SYNC
RFI /* jump to handler, enable MMU */
+99: b ret_from_kernel_syscall
.endm
.macro save_dar_dsisr_on_stack reg1, reg2, sp
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h
index 37fc84ed90e3..bd2e5ed8dd50 100644
--- a/arch/powerpc/kernel/head_booke.h
+++ b/arch/powerpc/kernel/head_booke.h
@@ -104,16 +104,18 @@ FTR_SECTION_ELSE
#ifdef CONFIG_KVM_BOOKE_HV
ALT_FTR_SECTION_END_IFSET(CPU_FTR_EMB_HV)
#endif
+ mfspr r9, SPRN_SRR1
BOOKE_CLEAR_BTB(r11)
+ andi. r11, r9, MSR_PR
lwz r11, TASK_STACK - THREAD(r10)
rlwinm r12,r12,0,4,2 /* Clear SO bit in CR */
+ beq- 99f
ALLOC_STACK_FRAME(r11, THREAD_SIZE - INT_FRAME_SIZE)
stw r12, _CCR(r11) /* save various registers */
mflr r12
stw r12,_LINK(r11)
mfspr r12,SPRN_SRR0
stw r1, GPR1(r11)
- mfspr r9,SPRN_SRR1
stw r1, 0(r11)
mr r1, r11
stw r12,_NIP(r11)
@@ -176,6 +178,7 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_EMB_HV)
mtspr SPRN_SRR0,r11
SYNC
RFI /* jump to handler, enable MMU */
+99: b ret_from_kernel_syscall
.endm
/* To handle the additional exception priority levels on 40x and Book-E
--
2.25.0
^ permalink raw reply related
* Re: powerpc Linux scv support and scv system call ABI proposal
From: Adhemerval Zanella @ 2020-01-31 11:30 UTC (permalink / raw)
To: Segher Boessenkool
Cc: Florian Weimer, libc-alpha, Tulio Magno Quites Machado Filho,
linuxppc-dev, Nicholas Piggin
In-Reply-To: <20200130214105.GX22482@gate.crashing.org>
On 30/01/2020 18:41, Segher Boessenkool wrote:
> Hi!
>
> On Thu, Jan 30, 2020 at 02:04:51PM -0300, Adhemerval Zanella wrote:
>> On 30/01/2020 10:50, Segher Boessenkool wrote:
>>> On Thu, Jan 30, 2020 at 01:03:53PM +0100, Florian Weimer wrote:
>>>>> This is why that *is* the only supported use. The documentation could
>>>>> use a touch-up, I think. Unless we still have problems here?
>>>>
>>>> I really don't know. GCC still has *some* support for the old behavior,
>>>> though.
>>>
>>> No. No support. It still does some of the same things, but that can
>>> change (and probably should). But this hasn't been supported since the
>>> dark ages, and the documentation has become gradually more explicit
>>> about it.
>>>
>>
>> I think this might be related to an odd sparc32 issue I am seeing with
>> newer clock_nanosleep. The expanded code is:
>>
>> --
>> register long err __asm__("g1"); // INTERNAL_SYSCALL_DECL (err)
>> r = ({ // r = INTERNAL_SYSCALL_CANCEL (...)
>> long int sc_ret;
>> if (SINGLE_THREAD_P)
>> sc_ret = INTERNAL_SYSCALL_CALL (__VA_ARGS__);
>> else
>> {
>> int sc_cancel_oldtype = __libc_enable_asynccancel ();
>> sc_ret = INTERNAL_SYSCALL_CALL (__VA_ARGS__); // It issues the syscall with the asm (...)
>> __librt_disable_asynccancel (sc_cancel_oldtype);
>> }
>> sc_ret;
>> });
>> if ((void) (val), __builtin_expect((err) != 0, 0)) // if (! INTERNAL_SYSCALL_ERROR_P (r, err))
>> return 0;
>> if ((-(val)) != ENOSYS) // if (INTERNAL_SYSCALL_ERRNO (r, err) != ENOSYS)
>> return ((-(val))); // return INTERNAL_SYSCALL_ERRNO (r, err);
>>
>> [...]
>>
>> r = ({ // r = INTERNAL_SYSCALL_CANCEL (...)
>> [...]
>> )}
>> if ((void) (val), __builtin_expect((err) != 0, 0)) // if (! INTERNAL_SYSCALL_ERROR_P (r, err))
>> {
>> [...]
>> }
>> return ((void) (val), __builtin_expect((err) != 0, 0)) // return (INTERNAL_SYSCALL_ERROR_P (r, err)
>> ? ((-(val))) : 0; // ? INTERNAL_SYSCALL_ERRNO (r, err) : 0);
>> --
>>
>> It requires that 'err' (assigned to 'g1')
>
> What do you mean by "assigned to g1"?
I meant 'err' being a local register variable.
>
>> be value propagated over
>> functions calls and over different scopes, which I take from your
>> explanation is not supported and fragile.
>
> You probably misundertand that, but let me ask: where is err assigned to
> at all in the code you quoted? I don't see it. Maybe it's hidden in some
> macro?
Indeed it was not explicit in the example code, it is burried in the
INTERNAL_SYSCALL_CALL macro which calls sparc-defined macros. For instance,
with 6 argument kernel syscall, it issues:
#define inline_syscall6(string,err,name,arg1,arg2,arg3,arg4,arg5,arg6) \
({ \
register long __o0 __asm__ ("o0") = (long)(arg1); \
register long __o1 __asm__ ("o1") = (long)(arg2); \
register long __o2 __asm__ ("o2") = (long)(arg3); \
register long __o3 __asm__ ("o3") = (long)(arg4); \
register long __o4 __asm__ ("o4") = (long)(arg5); \
register long __o5 __asm__ ("o5") = (long)(arg6); \
err = name; \
__asm __volatile (string : "=r" (err), "=r" (__o0) : \
"0" (err), "1" (__o0), "r" (__o1), \
"r" (__o2), "r" (__o3), "r" (__o4), \
"r" (__o5) : \
__SYSCALL_CLOBBERS); \
__o0; \
})
Where 'err' defined by 'INTERNAL_SYSCALL_DECL' should be the 'err' macro
argument.
>
> Or, maybe some asm writes to g1? This is explicitly not okay (quote
> from the GCC manual):
Yes, that's the case.
>
> Defining a register variable does not reserve the register. Other than
> when invoking the Extended 'asm', the contents of the specified register
> are not guaranteed. For this reason, the following uses are explicitly
> _not_ supported. If they appear to work, it is only happenstance, and
> may stop working as intended due to (seemingly) unrelated changes in
> surrounding code, or even minor changes in the optimization of a future
> version of gcc:
>
> * Passing parameters to or from Basic 'asm'
> * Passing parameters to or from Extended 'asm' without using input or
> output operands.
> * Passing parameters to or from routines written in assembler (or
> other languages) using non-standard calling conventions.
>
>> It also seems that if I
>> move the __libc_enable_* calls before 'err' initialization and after
>> its usage the code seems to works, but again it seems this usage
>> is not really supported on gcc.
>>
>> So it seems that the current usage of 'INTERNAL_SYSCALL_DECL' and
>> 'INTERNAL_SYSCALL_ERROR_P' are fragile if the architecture *does*
>> use the 'err' variable and it is defined a register alias (which
>> its the case only for sparc currently).
>>
>> Although a straightforward for sparc would be redefine
>> INTERNAL_SYSCALL_DECL to not use a register alias, I still think
>> we should just follow Linux kernel ABI convention where value in
>> the range between -4095 and -1 indicates an error and handle any
>> specific symbols that might not strictly follow it with an
>> arch-specific implementation (as we do for lseek on x32 and
>> mips64n32). It would allow cleanup a lot of code and avoid such
>> pitfalls.
>
> I don't really understand what you call a "register alias", either.
> (And i don't know the Sparc ABI well enough to help you with that).
I meant a register variable where its use 'after' the extended asm
is expected to use the define register.
^ permalink raw reply
* Re: [PATCH] of: Add OF_DMA_DEFAULT_COHERENT & select it on powerpc
From: Michael Ellerman @ 2020-01-31 10:40 UTC (permalink / raw)
To: Rob Herring
Cc: devicetree, ulf.hansson, linux-kernel, linuxppc-dev, robh+dt,
chzigotzky, hch
In-Reply-To: <20200128142646.GA17341@bogus>
Rob Herring <robh@kernel.org> writes:
> On Sun, 26 Jan 2020 22:52:47 +1100, Michael Ellerman wrote:
>> There's an OF helper called of_dma_is_coherent(), which checks if a
>> device has a "dma-coherent" property to see if the device is coherent
>> for DMA.
>>
>> But on some platforms devices are coherent by default, and on some
>> platforms it's not possible to update existing device trees to add the
>> "dma-coherent" property.
>>
>> So add a Kconfig symbol to allow arch code to tell
>> of_dma_is_coherent() that devices are coherent by default, regardless
>> of the presence of the property.
>>
>> Select that symbol on powerpc when NOT_COHERENT_CACHE is not set, ie.
>> when the system has a coherent cache.
>>
>> Fixes: 92ea637edea3 ("of: introduce of_dma_is_coherent() helper")
>> Cc: stable@vger.kernel.org # v3.16+
>> Reported-by: Christian Zigotzky <chzigotzky@xenosoft.de>
>> Tested-by: Christian Zigotzky <chzigotzky@xenosoft.de>
>> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
>> ---
>> arch/powerpc/Kconfig | 1 +
>> drivers/of/Kconfig | 4 ++++
>> drivers/of/address.c | 6 +++++-
>> 3 files changed, 10 insertions(+), 1 deletion(-)
>>
>
> Applied, thanks.
Thanks.
cheers
^ permalink raw reply
* Re: [PATCH] of: Add OF_DMA_DEFAULT_COHERENT & select it on powerpc
From: Michael Ellerman @ 2020-01-31 10:40 UTC (permalink / raw)
To: Ulf Hansson
Cc: DTML, Linux Kernel Mailing List, linuxppc-dev, Rob Herring,
Christian Zigotzky, Christoph Hellwig
In-Reply-To: <CAPDyKFrbYmV6_nV6psVLq6VRKMXf0PXpemBbj48yjOr3P130BA@mail.gmail.com>
Ulf Hansson <ulf.hansson@linaro.org> writes:
> On Sun, 26 Jan 2020 at 12:53, Michael Ellerman <mpe@ellerman.id.au> wrote:
>> There's an OF helper called of_dma_is_coherent(), which checks if a
>> device has a "dma-coherent" property to see if the device is coherent
>> for DMA.
>>
>> But on some platforms devices are coherent by default, and on some
>> platforms it's not possible to update existing device trees to add the
>> "dma-coherent" property.
>>
>> So add a Kconfig symbol to allow arch code to tell
>> of_dma_is_coherent() that devices are coherent by default, regardless
>> of the presence of the property.
>>
>> Select that symbol on powerpc when NOT_COHERENT_CACHE is not set, ie.
>> when the system has a coherent cache.
>>
>> Fixes: 92ea637edea3 ("of: introduce of_dma_is_coherent() helper")
>> Cc: stable@vger.kernel.org # v3.16+
>> Reported-by: Christian Zigotzky <chzigotzky@xenosoft.de>
>> Tested-by: Christian Zigotzky <chzigotzky@xenosoft.de>
>> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
>
> Thanks Michael for helping out fixing and this! The patch looks good to me.
>
> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Thanks for the review.
cheers
^ permalink raw reply
* Re: [PATCH 1/2] pseries/vio: Remove stray #ifdef CONFIG_PPC_PSERIES
From: Michael Ellerman @ 2020-01-31 10:38 UTC (permalink / raw)
To: Oliver O'Halloran, linuxppc-dev; +Cc: Oliver O'Halloran
In-Reply-To: <20200130063153.19915-1-oohall@gmail.com>
Subject: Re: [PATCH 1/2] pseries/vio: Remove stray #ifdef CONFIG_PPC_PSERIES
^
powerpc/
Please.
I'll fix it up.
Oliver O'Halloran <oohall@gmail.com> writes:
> vio.c requires CONFIG_IBMVIO which in turn depends on PPC_PSERIES.
> In other words, this ifdef is pointless.
And all of platforms/pseries is only built if PPC_PSERIES=y.
> At a guess it's a carry-over from pre-history.
It's not pre-history. Probably should have been cleaned up in:
commit b0787660260604ba63621881851de0032279819b
Author: Stephen Rothwell <sfr@canb.auug.org.au>
AuthorDate: Wed Mar 7 18:43:10 2012 +0000
Commit: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CommitDate: Fri Mar 9 10:35:23 2012 +1100
powerpc: clean up vio.c
This cleans up vio.c after the removal of the legacy iSeries platform.
It also removes some no longer referenced include files.
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
cheers
> diff --git a/arch/powerpc/platforms/pseries/vio.c b/arch/powerpc/platforms/pseries/vio.c
> index f682b7b..37f1f25 100644
> --- a/arch/powerpc/platforms/pseries/vio.c
> +++ b/arch/powerpc/platforms/pseries/vio.c
> @@ -1628,7 +1628,6 @@ const void *vio_get_attribute(struct vio_dev *vdev, char *which, int *length)
> }
> EXPORT_SYMBOL(vio_get_attribute);
>
> -#ifdef CONFIG_PPC_PSERIES
> /* vio_find_name() - internal because only vio.c knows how we formatted the
> * kobject name
> */
> @@ -1698,7 +1697,6 @@ int vio_disable_interrupts(struct vio_dev *dev)
> return rc;
> }
> EXPORT_SYMBOL(vio_disable_interrupts);
> -#endif /* CONFIG_PPC_PSERIES */
>
> static int __init vio_init(void)
> {
> --
> 2.9.5
^ 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