* [PATCH v2 4/7] dt-bindings: counter: ftm-quaddec
From: Patrick Havelange @ 2019-03-06 11:12 UTC (permalink / raw)
To: William Breathitt Gray, Rob Herring, Mark Rutland, Shawn Guo,
Li Yang, Daniel Lezcano, Thomas Gleixner, Thierry Reding,
Esben Haabendal, linux-iio, linux-kernel, devicetree,
linux-arm-kernel, linux-pwm, linuxppc-dev, Jonathan Cameron
Cc: Patrick Havelange
In-Reply-To: <20190306111208.7454-1-patrick.havelange@essensium.com>
FlexTimer quadrature decoder driver.
Signed-off-by: Patrick Havelange <patrick.havelange@essensium.com>
Reviewed-by: Esben Haabendal <esben@haabendal.dk>
---
Changes v2
- None
---
.../bindings/counter/ftm-quaddec.txt | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
create mode 100644 Documentation/devicetree/bindings/counter/ftm-quaddec.txt
diff --git a/Documentation/devicetree/bindings/counter/ftm-quaddec.txt b/Documentation/devicetree/bindings/counter/ftm-quaddec.txt
new file mode 100644
index 000000000000..4d18cd722074
--- /dev/null
+++ b/Documentation/devicetree/bindings/counter/ftm-quaddec.txt
@@ -0,0 +1,18 @@
+FlexTimer Quadrature decoder counter
+
+This driver exposes a simple counter for the quadrature decoder mode.
+
+Required properties:
+- compatible: Must be "fsl,ftm-quaddec".
+- reg: Must be set to the memory region of the flextimer.
+
+Optional property:
+- big-endian: Access the device registers in big-endian mode.
+
+Example:
+ counter0: counter@29d0000 {
+ compatible = "fsl,ftm-quaddec";
+ reg = <0x0 0x29d0000 0x0 0x10000>;
+ big-endian;
+ status = "disabled";
+ };
--
2.19.1
^ permalink raw reply related
* [PATCH v2 3/7] drivers/clocksource: timer-fsl-ftm: use common header for FlexTimer #defines
From: Patrick Havelange @ 2019-03-06 11:12 UTC (permalink / raw)
To: William Breathitt Gray, Rob Herring, Mark Rutland, Shawn Guo,
Li Yang, Daniel Lezcano, Thomas Gleixner, Thierry Reding,
Esben Haabendal, linux-iio, linux-kernel, devicetree,
linux-arm-kernel, linux-pwm, linuxppc-dev, Jonathan Cameron
Cc: Patrick Havelange
In-Reply-To: <20190306111208.7454-1-patrick.havelange@essensium.com>
Common #defines have been moved to "linux/fsl/ftm.h". Thus making use of
this file.
Also FTM_SC_CLK_SHIFT has been renamed to FTM_SC_CLK_MASK_SHIFT.
Signed-off-by: Patrick Havelange <patrick.havelange@essensium.com>
Reviewed-by: Esben Haabendal <esben@haabendal.dk>
---
Changes v2
- None
---
drivers/clocksource/timer-fsl-ftm.c | 15 ++-------------
1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/drivers/clocksource/timer-fsl-ftm.c b/drivers/clocksource/timer-fsl-ftm.c
index 846d18daf893..e1c34b2f53a5 100644
--- a/drivers/clocksource/timer-fsl-ftm.c
+++ b/drivers/clocksource/timer-fsl-ftm.c
@@ -19,20 +19,9 @@
#include <linux/of_irq.h>
#include <linux/sched_clock.h>
#include <linux/slab.h>
+#include <linux/fsl/ftm.h>
-#define FTM_SC 0x00
-#define FTM_SC_CLK_SHIFT 3
-#define FTM_SC_CLK_MASK (0x3 << FTM_SC_CLK_SHIFT)
-#define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_SHIFT)
-#define FTM_SC_PS_MASK 0x7
-#define FTM_SC_TOIE BIT(6)
-#define FTM_SC_TOF BIT(7)
-
-#define FTM_CNT 0x04
-#define FTM_MOD 0x08
-#define FTM_CNTIN 0x4C
-
-#define FTM_PS_MAX 7
+#define FTM_SC_CLK(c) ((c) << FTM_SC_CLK_MASK_SHIFT)
struct ftm_clock_device {
void __iomem *clksrc_base;
--
2.19.1
^ permalink raw reply related
* [PATCH v2 2/7] drivers/pwm: pwm-fsl-ftm: use common header for FlexTimer #defines
From: Patrick Havelange @ 2019-03-06 11:12 UTC (permalink / raw)
To: William Breathitt Gray, Rob Herring, Mark Rutland, Shawn Guo,
Li Yang, Daniel Lezcano, Thomas Gleixner, Thierry Reding,
Esben Haabendal, linux-iio, linux-kernel, devicetree,
linux-arm-kernel, linux-pwm, linuxppc-dev, Jonathan Cameron
Cc: Patrick Havelange
In-Reply-To: <20190306111208.7454-1-patrick.havelange@essensium.com>
This also fixes the wrong value for the previously defined
FTM_MODE_INIT macro (it was not used).
Signed-off-by: Patrick Havelange <patrick.havelange@essensium.com>
Reviewed-by: Esben Haabendal <esben@haabendal.dk>
---
Changes v2
- None
---
drivers/pwm/pwm-fsl-ftm.c | 44 +--------------------------------------
1 file changed, 1 insertion(+), 43 deletions(-)
diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c
index 883378d055c6..f21ea1b97116 100644
--- a/drivers/pwm/pwm-fsl-ftm.c
+++ b/drivers/pwm/pwm-fsl-ftm.c
@@ -22,51 +22,9 @@
#include <linux/pwm.h>
#include <linux/regmap.h>
#include <linux/slab.h>
+#include <linux/fsl/ftm.h>
-#define FTM_SC 0x00
-#define FTM_SC_CLK_MASK_SHIFT 3
-#define FTM_SC_CLK_MASK (3 << FTM_SC_CLK_MASK_SHIFT)
#define FTM_SC_CLK(c) (((c) + 1) << FTM_SC_CLK_MASK_SHIFT)
-#define FTM_SC_PS_MASK 0x7
-
-#define FTM_CNT 0x04
-#define FTM_MOD 0x08
-
-#define FTM_CSC_BASE 0x0C
-#define FTM_CSC_MSB BIT(5)
-#define FTM_CSC_MSA BIT(4)
-#define FTM_CSC_ELSB BIT(3)
-#define FTM_CSC_ELSA BIT(2)
-#define FTM_CSC(_channel) (FTM_CSC_BASE + ((_channel) * 8))
-
-#define FTM_CV_BASE 0x10
-#define FTM_CV(_channel) (FTM_CV_BASE + ((_channel) * 8))
-
-#define FTM_CNTIN 0x4C
-#define FTM_STATUS 0x50
-
-#define FTM_MODE 0x54
-#define FTM_MODE_FTMEN BIT(0)
-#define FTM_MODE_INIT BIT(2)
-#define FTM_MODE_PWMSYNC BIT(3)
-
-#define FTM_SYNC 0x58
-#define FTM_OUTINIT 0x5C
-#define FTM_OUTMASK 0x60
-#define FTM_COMBINE 0x64
-#define FTM_DEADTIME 0x68
-#define FTM_EXTTRIG 0x6C
-#define FTM_POL 0x70
-#define FTM_FMS 0x74
-#define FTM_FILTER 0x78
-#define FTM_FLTCTRL 0x7C
-#define FTM_QDCTRL 0x80
-#define FTM_CONF 0x84
-#define FTM_FLTPOL 0x88
-#define FTM_SYNCONF 0x8C
-#define FTM_INVCTRL 0x90
-#define FTM_SWOCTRL 0x94
-#define FTM_PWMLOAD 0x98
enum fsl_pwm_clk {
FSL_PWM_CLK_SYS,
--
2.19.1
^ permalink raw reply related
* [PATCH v2 1/7] include/fsl: add common FlexTimer #defines in a separate header.
From: Patrick Havelange @ 2019-03-06 11:12 UTC (permalink / raw)
To: William Breathitt Gray, Rob Herring, Mark Rutland, Shawn Guo,
Li Yang, Daniel Lezcano, Thomas Gleixner, Thierry Reding,
Esben Haabendal, linux-iio, linux-kernel, devicetree,
linux-arm-kernel, linux-pwm, linuxppc-dev, Jonathan Cameron
Cc: Patrick Havelange
In-Reply-To: <20190306111208.7454-1-patrick.havelange@essensium.com>
Several files are/will be using the same #defines to use the Flextimer
module. Regroup them in a common file.
Signed-off-by: Patrick Havelange <patrick.havelange@essensium.com>
Reviewed-by: Esben Haabendal <esben@haabendal.dk>
---
Changes v2
- Commit message
---
include/linux/fsl/ftm.h | 88 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)
create mode 100644 include/linux/fsl/ftm.h
diff --git a/include/linux/fsl/ftm.h b/include/linux/fsl/ftm.h
new file mode 100644
index 000000000000..d59011acf66c
--- /dev/null
+++ b/include/linux/fsl/ftm.h
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef __FSL_FTM_H__
+#define __FSL_FTM_H__
+
+#define FTM_SC 0x0 /* Status And Control */
+#define FTM_CNT 0x4 /* Counter */
+#define FTM_MOD 0x8 /* Modulo */
+
+#define FTM_CNTIN 0x4C /* Counter Initial Value */
+#define FTM_STATUS 0x50 /* Capture And Compare Status */
+#define FTM_MODE 0x54 /* Features Mode Selection */
+#define FTM_SYNC 0x58 /* Synchronization */
+#define FTM_OUTINIT 0x5C /* Initial State For Channels Output */
+#define FTM_OUTMASK 0x60 /* Output Mask */
+#define FTM_COMBINE 0x64 /* Function For Linked Channels */
+#define FTM_DEADTIME 0x68 /* Deadtime Insertion Control */
+#define FTM_EXTTRIG 0x6C /* FTM External Trigger */
+#define FTM_POL 0x70 /* Channels Polarity */
+#define FTM_FMS 0x74 /* Fault Mode Status */
+#define FTM_FILTER 0x78 /* Input Capture Filter Control */
+#define FTM_FLTCTRL 0x7C /* Fault Control */
+#define FTM_QDCTRL 0x80 /* Quadrature Decoder Control And Status */
+#define FTM_CONF 0x84 /* Configuration */
+#define FTM_FLTPOL 0x88 /* FTM Fault Input Polarity */
+#define FTM_SYNCONF 0x8C /* Synchronization Configuration */
+#define FTM_INVCTRL 0x90 /* FTM Inverting Control */
+#define FTM_SWOCTRL 0x94 /* FTM Software Output Control */
+#define FTM_PWMLOAD 0x98 /* FTM PWM Load */
+
+#define FTM_SC_CLK_MASK_SHIFT 3
+#define FTM_SC_CLK_MASK (3 << FTM_SC_CLK_MASK_SHIFT)
+#define FTM_SC_TOF 0x80
+#define FTM_SC_TOIE 0x40
+#define FTM_SC_CPWMS 0x20
+#define FTM_SC_CLKS 0x18
+#define FTM_SC_PS_1 0x0
+#define FTM_SC_PS_2 0x1
+#define FTM_SC_PS_4 0x2
+#define FTM_SC_PS_8 0x3
+#define FTM_SC_PS_16 0x4
+#define FTM_SC_PS_32 0x5
+#define FTM_SC_PS_64 0x6
+#define FTM_SC_PS_128 0x7
+#define FTM_SC_PS_MASK 0x7
+
+#define FTM_MODE_FAULTIE 0x80
+#define FTM_MODE_FAULTM 0x60
+#define FTM_MODE_CAPTEST 0x10
+#define FTM_MODE_PWMSYNC 0x8
+#define FTM_MODE_WPDIS 0x4
+#define FTM_MODE_INIT 0x2
+#define FTM_MODE_FTMEN 0x1
+
+/* NXP Errata: The PHAFLTREN and PHBFLTREN bits are tide to zero internally
+ * and these bits cannot be set. Flextimer cannot use Filter in
+ * Quadrature Decoder Mode.
+ * https://community.nxp.com/thread/467648#comment-1010319
+ */
+#define FTM_QDCTRL_PHAFLTREN 0x80
+#define FTM_QDCTRL_PHBFLTREN 0x40
+#define FTM_QDCTRL_PHAPOL 0x20
+#define FTM_QDCTRL_PHBPOL 0x10
+#define FTM_QDCTRL_QUADMODE 0x8
+#define FTM_QDCTRL_QUADDIR 0x4
+#define FTM_QDCTRL_TOFDIR 0x2
+#define FTM_QDCTRL_QUADEN 0x1
+
+#define FTM_FMS_FAULTF 0x80
+#define FTM_FMS_WPEN 0x40
+#define FTM_FMS_FAULTIN 0x10
+#define FTM_FMS_FAULTF3 0x8
+#define FTM_FMS_FAULTF2 0x4
+#define FTM_FMS_FAULTF1 0x2
+#define FTM_FMS_FAULTF0 0x1
+
+#define FTM_CSC_BASE 0xC
+#define FTM_CSC_MSB 0x20
+#define FTM_CSC_MSA 0x10
+#define FTM_CSC_ELSB 0x8
+#define FTM_CSC_ELSA 0x4
+#define FTM_CSC(_channel) (FTM_CSC_BASE + ((_channel) * 8))
+
+#define FTM_CV_BASE 0x10
+#define FTM_CV(_channel) (FTM_CV_BASE + ((_channel) * 8))
+
+#define FTM_PS_MAX 7
+
+#endif
--
2.19.1
^ permalink raw reply related
* [PATCH v2 0/7] FlexTimer Module Quadrature decoder counter
From: Patrick Havelange @ 2019-03-06 11:12 UTC (permalink / raw)
To: William Breathitt Gray, Rob Herring, Mark Rutland, Shawn Guo,
Li Yang, Daniel Lezcano, Thomas Gleixner, Thierry Reding,
Esben Haabendal, linux-iio, linux-kernel, devicetree,
linux-arm-kernel, linux-pwm, linuxppc-dev, Jonathan Cameron
Cc: Patrick Havelange
This patch serie is to be applied on top of
https://patchwork.kernel.org/project/linux-iio/list/?series=147
(a more recent version of the serie is available here :
https://gitlab.com/vilhelmgray/iio/tree/generic_counter_v10 )
Main changes in v2:
The code is a bit simpler, thanks to more use of devm_* functions.
The polling/32bit signed version has been dropped, as not needed and
no other driver is doing that.
Patrick Havelange (7):
include/fsl: add common FlexTimer #defines in a separate header.
drivers/pwm: pwm-fsl-ftm: use common header for FlexTimer #defines
drivers/clocksource: timer-fsl-ftm: use common header for FlexTimer
#defines
dt-bindings: counter: ftm-quaddec
counter: add FlexTimer Module Quadrature decoder counter driver
counter: ftm-quaddec: Documentation: Add specific counter sysfs
documentation
LS1021A: dtsi: add ftm quad decoder entries
.../ABI/testing/sysfs-bus-counter-ftm-quaddec | 16 +
.../bindings/counter/ftm-quaddec.txt | 18 +
arch/arm/boot/dts/ls1021a.dtsi | 28 ++
drivers/clocksource/timer-fsl-ftm.c | 15 +-
drivers/counter/Kconfig | 9 +
drivers/counter/Makefile | 1 +
drivers/counter/ftm-quaddec.c | 356 ++++++++++++++++++
drivers/pwm/pwm-fsl-ftm.c | 44 +--
include/linux/fsl/ftm.h | 88 +++++
9 files changed, 519 insertions(+), 56 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-bus-counter-ftm-quaddec
create mode 100644 Documentation/devicetree/bindings/counter/ftm-quaddec.txt
create mode 100644 drivers/counter/ftm-quaddec.c
create mode 100644 include/linux/fsl/ftm.h
--
2.19.1
^ permalink raw reply
* Re: [PATCH 2/2] mm/dax: Don't enable huge dax mapping by default
From: Aneesh Kumar K.V @ 2019-03-06 9:17 UTC (permalink / raw)
To: Dan Williams, Oliver
Cc: Jan Kara, linux-nvdimm, Linux Kernel Mailing List, Linux MM,
Ross Zwisler, Andrew Morton, linuxppc-dev, Kirill A . Shutemov
In-Reply-To: <CAPcyv4jhEvijybSVsy+wmvgqfvyxfePQ3PUqy1hhmVmPtJTyqQ@mail.gmail.com>
Dan Williams <dan.j.williams@intel.com> writes:
> On Thu, Feb 28, 2019 at 1:40 AM Oliver <oohall@gmail.com> wrote:
>>
>> On Thu, Feb 28, 2019 at 7:35 PM Aneesh Kumar K.V
>> <aneesh.kumar@linux.ibm.com> wrote:
>> >
>> > Add a flag to indicate the ability to do huge page dax mapping. On architecture
>> > like ppc64, the hypervisor can disable huge page support in the guest. In
>> > such a case, we should not enable huge page dax mapping. This patch adds
>> > a flag which the architecture code will update to indicate huge page
>> > dax mapping support.
>>
>> *groan*
>>
>> > Architectures mostly do transparent_hugepage_flag = 0; if they can't
>> > do hugepages. That also takes care of disabling dax hugepage mapping
>> > with this change.
>> >
>> > Without this patch we get the below error with kvm on ppc64.
>> >
>> > [ 118.849975] lpar: Failed hash pte insert with error -4
>> >
>> > NOTE: The patch also use
>> >
>> > echo never > /sys/kernel/mm/transparent_hugepage/enabled
>> > to disable dax huge page mapping.
>> >
>> > Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
>> > ---
>> > TODO:
>> > * Add Fixes: tag
>> >
>> > include/linux/huge_mm.h | 4 +++-
>> > mm/huge_memory.c | 4 ++++
>> > 2 files changed, 7 insertions(+), 1 deletion(-)
>> >
>> > diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
>> > index 381e872bfde0..01ad5258545e 100644
>> > --- a/include/linux/huge_mm.h
>> > +++ b/include/linux/huge_mm.h
>> > @@ -53,6 +53,7 @@ vm_fault_t vmf_insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,
>> > pud_t *pud, pfn_t pfn, bool write);
>> > enum transparent_hugepage_flag {
>> > TRANSPARENT_HUGEPAGE_FLAG,
>> > + TRANSPARENT_HUGEPAGE_DAX_FLAG,
>> > TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG,
>> > TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG,
>> > TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG,
>> > @@ -111,7 +112,8 @@ static inline bool __transparent_hugepage_enabled(struct vm_area_struct *vma)
>> > if (transparent_hugepage_flags & (1 << TRANSPARENT_HUGEPAGE_FLAG))
>> > return true;
>> >
>> > - if (vma_is_dax(vma))
>> > + if (vma_is_dax(vma) &&
>> > + (transparent_hugepage_flags & (1 << TRANSPARENT_HUGEPAGE_DAX_FLAG)))
>> > return true;
>>
>> Forcing PTE sized faults should be fine for fsdax, but it'll break
>> devdax. The devdax driver requires the fault size be >= the namespace
>> alignment since devdax tries to guarantee hugepage mappings will be
>> used and PMD alignment is the default. We can probably have devdax
>> fall back to the largest size the hypervisor has made available, but
>> it does run contrary to the design. Ah well, I suppose it's better off
>> being degraded rather than unusable.
>
> Given this is an explicit setting I think device-dax should explicitly
> fail to enable in the presence of this flag to preserve the
> application visible behavior.
>
> I.e. if device-dax was enabled after this setting was made then I
> think future faults should fail as well.
Not sure I understood that. Now we are disabling the ability to map
pages as huge pages. I am now considering that this should not be
user configurable. Ie, this is something that platform can use to avoid
dax forcing huge page mapping, but if the architecture can enable huge
dax mapping, we should always default to using that.
Now w.r.t to failures, can device-dax do an opportunistic huge page
usage? I haven't looked at the device-dax details fully yet. Do we make the
assumption of the mapping page size as a format w.r.t device-dax? Is that
derived from nd_pfn->align value?
Here is what I am working on:
1) If the platform doesn't support huge page and if the device superblock
indicated that it was created with huge page support, we fail the device
init.
2) Now if we are creating a new namespace without huge page support in
the platform, then we force the align details to PAGE_SIZE. In such a
configuration when handling dax fault even with THP enabled during
the build, we should not try to use hugepage. This I think we can
achieve by using TRANSPARENT_HUGEPAEG_DAX_FLAG.
Also even if the user decided to not use THP, by
echo "never" > transparent_hugepage/enabled , we should continue to map
dax fault using huge page on platforms that can support huge pages.
This still doesn't cover the details of a device-dax created with
PAGE_SIZE align later booted with a kernel that can do hugepage dax.How
should we handle that? That makes me think, this should be a VMA flag
which got derived from device config? May be use VM_HUGEPAGE to indicate
if device should use a hugepage mapping or not?
-aneesh
^ permalink raw reply
* [PATCH] powerpc: Add barrier_nospec to raw_copy_in_user()
From: Suraj Jitindar Singh @ 2019-03-06 1:10 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Suraj Jitindar Singh
Commit ddf35cf3764b ("powerpc: Use barrier_nospec in copy_from_user()")
Added barrier_nospec before loading from user-controller pointers.
The intention was to order the load from the potentially user-controlled
pointer vs a previous branch based on an access_ok() check or similar.
In order to achieve the same result, add a barrier_nospec to the
raw_copy_in_user() function before loading from such a user-controlled
pointer.
Signed-off-by: Suraj Jitindar Singh <sjitindarsingh@gmail.com>
---
arch/powerpc/include/asm/uaccess.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index e3a731793ea2..bb615592d5bb 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -306,6 +306,7 @@ extern unsigned long __copy_tofrom_user(void __user *to,
static inline unsigned long
raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
{
+ barrier_nospec();
return __copy_tofrom_user(to, from, n);
}
#endif /* __powerpc64__ */
--
2.13.6
^ permalink raw reply related
* Re: [PATCH 0/2] PCI/AER: Consistently use _OSC to determine who owns AER
From: Bjorn Helgaas @ 2019-03-05 23:16 UTC (permalink / raw)
To: Alexandru Gagniuc
Cc: alex_gagniuc, helgaas, Sam Bobroff, linux-pci, Shyam_Iyer,
Rafael J. Wysocki, linux-kernel, keith.busch, linux-acpi, lukas,
Oliver O'Halloran, austin_bolen, linuxppc-dev, Len Brown
In-Reply-To: <20181115231605.24352-1-mr.nuke.me@gmail.com>
On Thu, Nov 15, 2018 at 05:16:01PM -0600, Alexandru Gagniuc wrote:
> Thanks to Keith for pointing out that it doesn't make sense to disable
> AER services when only one device has a FIRMWARE_FIRST HEST.
>
> AER ownership is an interesting issue brought in by FFS (firmware-first)
> model. In a nutshell if FFS handles AER, then OS should not touch any
> of the AER bits. FW might set things up so that it receives AER
> notifications via SMI. It's theoretically possible to receive SCIs,
> but the exact mechanism is platform-dependent. OS touching AER bits
> when firmware owns them may interfere with these notifications.
>
> The ACPI mechanism for negotiating control of AER is _OSC, and is
> described in detail in ACPI 6.2 Ch. 6.2.11.3. _OSC is negotiated at
> the root bus level. Any root port, switch, or endpoint under the bus
> would have its AER ownership negotiated in one _OSC call.
>
> Then there is HEST, which is part of ACPI Platform Error Interfaces
> (APEI). HEST tables describe the errors that FW may report to the OS.
> A types 6,7 and 7 HEST tables describe AER errors from PCIe devices.
> As part of this description, we're told if the error source is FFS.
>
> Information in HEST seems to be redundant, as each error reported by
> FW will have a CPER table that describes it in detail.
>
> Because HEST describes an error source as firmware-first or not, we've
> taken this to mean ownership of AER. Because AER ownership and error
> reporting are coupled, _OSC and HEST usually agree on the matter of
> ownership. However, that doesn't seem to be required by ACPI.
>
> I've asked around a few people at Dell and they unanimously agree that
> _OSC is the correct way to determine ownership of AER. In linux, we
> use the result of _OSC to enable AER services, but we use HEST to
> determine AER ownership. That's inconsistent. This series drops the
> use of HEST in favor of _OSC.
>
> [1] https://lkml.org/lkml/2018/11/15/62
>
> Alexandru Gagniuc (2):
> PCI/AER: Do not use APEI/HEST to disable AER services globally
> PCI/AER: Determine AER ownership based on _OSC instead of HEST
>
> drivers/acpi/pci_root.c | 9 +----
> drivers/pci/pcie/aer.c | 82 ++--------------------------------------
> include/linux/pci-acpi.h | 6 ---
> 3 files changed, 5 insertions(+), 92 deletions(-)
I'm pretty sure we do need to do something here, but there was quite a
lot of discussion that didn't seem to really get resolved, so I'm
dropping these for now.
Please repost them with any relevant updates and we'll see if we can
get a consensus that we're going the right direction.
Bjorn
^ permalink raw reply
* [PATCH 5/7] powerpc/8xx: Add Kernel Userspace Access Protection
From: Christophe Leroy @ 2019-03-05 21:18 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1551820474.git.christophe.leroy@c-s.fr>
This patch adds Kernel Userspace Access Protection on the 8xx.
When a page is RO or RW, it is set RO or RW for Key 0 and NA
for Key 1.
Up to now, the User group is defined with Key 0 for both User and
Supervisor.
By changing the group to Key 0 for User and Key 1 for Supervisor,
this patch prevents the Kernel from being able to access user data.
At exception entry, the kernel saves SPRN_MD_AP in the regs struct,
and reapply the protection. At exception exit it restores SPRN_MD_AP
with the value saved on exception entry.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/include/asm/kup.h | 3 ++
arch/powerpc/include/asm/nohash/32/kup-8xx.h | 52 ++++++++++++++++++++++++++++
arch/powerpc/include/asm/nohash/32/mmu-8xx.h | 7 ++++
arch/powerpc/mm/8xx_mmu.c | 12 +++++++
arch/powerpc/platforms/Kconfig.cputype | 1 +
5 files changed, 75 insertions(+)
create mode 100644 arch/powerpc/include/asm/nohash/32/kup-8xx.h
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index 51a55be70cbc..2ab9e904c22c 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -5,6 +5,9 @@
#ifdef CONFIG_PPC_BOOK3S_64
#include <asm/book3s/64/kup-radix.h>
#endif
+#ifdef CONFIG_PPC_8xx
+#include <asm/nohash/32/kup-8xx.h>
+#endif
#ifdef __ASSEMBLY__
#ifndef CONFIG_PPC_KUAP
diff --git a/arch/powerpc/include/asm/nohash/32/kup-8xx.h b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
new file mode 100644
index 000000000000..dbf0d7d40e7e
--- /dev/null
+++ b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_KUP_8XX_H_
+#define _ASM_POWERPC_KUP_8XX_H_
+
+#include <asm/bug.h>
+
+#ifdef CONFIG_PPC_KUAP
+
+#ifdef __ASSEMBLY__
+
+.macro kuap_save_and_lock sp, thread, gpr1, gpr2, gpr3
+ lis \gpr2, MD_APG_KUAP@h /* only APG0 and APG1 are used */
+ mfspr \gpr1, SPRN_MD_AP
+ mtspr SPRN_MD_AP, \gpr2
+ stw \gpr1, STACK_REGS_KUAP(\sp)
+.endm
+
+.macro kuap_restore sp, current, gpr1, gpr2, gpr3
+ lwz \gpr1, STACK_REGS_KUAP(\sp)
+ mtspr SPRN_MD_AP, \gpr1
+.endm
+
+.macro kuap_check current, gpr
+#ifdef CONFIG_PPC_KUAP_DEBUG
+ mfspr \gpr, SPRN_MD_AP
+ rlwinm \gpr, \gpr, 16, 0xffff
+999: twnei \gpr, MD_APG_KUAP@h
+ EMIT_BUG_ENTRY 999b, __FILE__, __LINE__, (BUGFLAG_WARNING | BUGFLAG_ONCE)
+#endif
+.endm
+
+#else /* !__ASSEMBLY__ */
+
+#include <asm/reg.h>
+
+static inline void allow_user_access(void __user *to, const void __user *from,
+ unsigned long size)
+{
+ mtspr(SPRN_MD_AP, MD_APG_INIT);
+}
+
+static inline void prevent_user_access(void __user *to, const void __user *from,
+ unsigned long size)
+{
+ mtspr(SPRN_MD_AP, MD_APG_KUAP);
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* CONFIG_PPC_KUAP */
+
+#endif /* _ASM_POWERPC_KUP_8XX_H_ */
diff --git a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
index 3cb743284e09..f620adef54fc 100644
--- a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
@@ -121,6 +121,13 @@
*/
#define MD_APG_INIT 0x4fffffff
+/*
+ * 0 => No user => 01 (all accesses performed according to page definition)
+ * 1 => User => 10 (all accesses performed according to swaped page definition)
+ * 2-16 => NA => 11 (all accesses performed as user iaw page definition)
+ */
+#define MD_APG_KUAP 0x6fffffff
+
/* The effective page number register. When read, contains the information
* about the last instruction TLB miss. When MD_RPN is written, bits in
* this register are used to create the TLB entry.
diff --git a/arch/powerpc/mm/8xx_mmu.c b/arch/powerpc/mm/8xx_mmu.c
index e257a0c9bd08..87648b58d295 100644
--- a/arch/powerpc/mm/8xx_mmu.c
+++ b/arch/powerpc/mm/8xx_mmu.c
@@ -225,3 +225,15 @@ void __init setup_kuep(bool disabled)
mtspr(SPRN_MI_AP, MI_APG_KUEP);
}
#endif
+
+#ifdef CONFIG_PPC_KUAP
+void __init setup_kuap(bool disabled)
+{
+ pr_info("Activating Kernel Userspace Access Protection\n");
+
+ if (disabled)
+ pr_warn("KUAP cannot be disabled yet on 8xx when compiled in\n");
+
+ mtspr(SPRN_MD_AP, MD_APG_KUAP);
+}
+#endif
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 00fa0d110dcb..ab586963893a 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -35,6 +35,7 @@ config PPC_8xx
select FSL_SOC
select SYS_SUPPORTS_HUGETLBFS
select PPC_HAVE_KUEP
+ select PPC_HAVE_KUAP
config 40x
bool "AMCC 40x"
--
2.13.3
^ permalink raw reply related
* [PATCH 7/7] powerpc/book3s32: Implement Kernel Userspace Access Protection
From: Christophe Leroy @ 2019-03-05 21:18 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1551820474.git.christophe.leroy@c-s.fr>
This patch implements Kernel Userspace Access Protection for
book3s/32.
Due to limitations of the processor page protection capabilities,
the protection is only against writing. read protection cannot be
achieved using page protection.
The previous patch modifies the page protection so that RW user
pages are RW for Key 0 and RO for Key 1, and it sets Key 0 for
both user and kernel.
This patch changes userspace segment registers are set to Ku 0
and Ks 1. When kernel needs to write to RW pages, the associated
segment register is then changed to Ks 0 in order to allow write
access to the kernel.
In order to avoid having the read all segment registers when
locking/unlocking the access, some data is kept in the thread_struct
and saved on stack on exceptions. The field identifies both the
first unlocked segment and the first segment following the last
unlocked one. When no segment is unlocked, it contains value 0.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/include/asm/book3s/32/kup.h | 96 ++++++++++++++++++++++++++++++++
arch/powerpc/include/asm/kup.h | 3 +
arch/powerpc/include/asm/processor.h | 3 +
arch/powerpc/kernel/asm-offsets.c | 3 +
arch/powerpc/kernel/head_32.S | 7 +++
arch/powerpc/mm/ppc_mmu_32.c | 10 ++++
arch/powerpc/platforms/Kconfig.cputype | 1 +
7 files changed, 123 insertions(+)
create mode 100644 arch/powerpc/include/asm/book3s/32/kup.h
diff --git a/arch/powerpc/include/asm/book3s/32/kup.h b/arch/powerpc/include/asm/book3s/32/kup.h
new file mode 100644
index 000000000000..3f02db633849
--- /dev/null
+++ b/arch/powerpc/include/asm/book3s/32/kup.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_BOOK3S_32_KUP_H
+#define _ASM_POWERPC_BOOK3S_32_KUP_H
+
+#ifdef CONFIG_PPC_KUAP
+
+#include <asm/book3s/32/mmu-hash.h>
+
+#ifdef __ASSEMBLY__
+
+.macro kuap_update_sr gpr1, gpr2, gpr3 /* NEVER use r0 as gpr2 due to addis */
+101: mtsrin \gpr1, \gpr2
+ addi \gpr1, \gpr1, 0x111 /* next VSID */
+ rlwinm \gpr1, \gpr1, 0, 0xf0ffffff /* clear VSID overflow */
+ addis \gpr2, \gpr2, 0x1000 /* address of next segment */
+ cmplw \gpr2, \gpr3
+ blt- 101b
+.endm
+
+.macro kuap_save_and_lock sp, thread, gpr1, gpr2, gpr3
+ lwz \gpr2, KUAP(\thread)
+ rlwinm. \gpr3, \gpr2, 28, 0xf0000000
+ stw \gpr2, STACK_REGS_KUAP(\sp)
+ beq+ 102f
+ li \gpr1, 0
+ stw \gpr1, KUAP(\thread)
+ mfsrin \gpr1, \gpr2
+ oris \gpr1, \gpr1, SR_KS@h /* set Ks */
+ kuap_update_sr \gpr1, \gpr2, \gpr3
+102:
+.endm
+
+.macro kuap_restore sp, current, gpr1, gpr2, gpr3
+ lwz \gpr2, STACK_REGS_KUAP(\sp)
+ rlwinm. \gpr3, \gpr2, 28, 0xf0000000
+ stw \gpr2, THREAD + KUAP(\current)
+ beq+ 102f
+ mfsrin \gpr1, \gpr2
+ rlwinm \gpr1, \gpr1, 0, ~SR_KS /* Clear Ks */
+ kuap_update_sr \gpr1, \gpr2, \gpr3
+102:
+.endm
+
+.macro kuap_check current, gpr
+#ifdef CONFIG_PPC_KUAP_DEBUG
+ lwz \gpr2, KUAP(thread)
+999: twnei \gpr, 0
+ EMIT_BUG_ENTRY 999b, __FILE__, __LINE__, (BUGFLAG_WARNING | BUGFLAG_ONCE)
+#endif
+.endm
+
+#else /* !__ASSEMBLY__ */
+
+#include <linux/sched.h>
+
+static inline void kuap_update_sr(u32 sr, u32 addr, u32 end)
+{
+ barrier(); /* make sure thread.kuap is updated before playing with SRs */
+ while (addr < end) {
+ mtsrin(sr, addr);
+ sr += 0x111; /* next VSID */
+ sr &= 0xf0ffffff; /* clear VSID overflow */
+ addr += 0x10000000; /* address of next segment */
+ }
+ isync(); /* Context sync required after mtsrin() */
+}
+
+static inline void allow_user_access(void __user *to, const void __user *from, u32 size)
+{
+ u32 addr = (u32)to;
+ u32 end = min(addr + size, TASK_SIZE);
+
+ if (!addr || addr >= TASK_SIZE || !size)
+ return;
+
+ current->thread.kuap = (addr & 0xf0000000) | ((((end - 1) >> 28) + 1) & 0xf);
+ kuap_update_sr(mfsrin(addr) & ~SR_KS, addr, end); /* Clear Ks */
+}
+
+static inline void prevent_user_access(void __user *to, const void __user *from, u32 size)
+{
+ u32 addr = (u32)to;
+ u32 end = min(addr + size, TASK_SIZE);
+
+ if (!addr || addr >= TASK_SIZE || !size)
+ return;
+
+ current->thread.kuap = 0;
+ kuap_update_sr(mfsrin(addr) | SR_KS, addr, end); /* set Ks */
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* CONFIG_PPC_KUAP */
+
+#endif /* _ASM_POWERPC_BOOK3S_32_KUP_H */
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index 2ab9e904c22c..2f42e8c19506 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -8,6 +8,9 @@
#ifdef CONFIG_PPC_8xx
#include <asm/nohash/32/kup-8xx.h>
#endif
+#ifdef CONFIG_PPC_BOOK3S_32
+#include <asm/book3s/32/kup.h>
+#endif
#ifdef __ASSEMBLY__
#ifndef CONFIG_PPC_KUAP
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 3351bcf42f2d..540949b397d4 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -164,6 +164,9 @@ struct thread_struct {
unsigned long rtas_sp; /* stack pointer for when in RTAS */
#endif
#endif
+#if defined(CONFIG_PPC_BOOK3S_32) && defined(CONFIG_PPC_KUAP)
+ unsigned long kuap; /* opened segments for user access */
+#endif
/* Debug Registers */
struct debug_reg debug;
struct thread_fp_state fp_state;
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 66202e02fee2..60b82198de7c 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -147,6 +147,9 @@ int main(void)
#if defined(CONFIG_KVM) && defined(CONFIG_BOOKE)
OFFSET(THREAD_KVM_VCPU, thread_struct, kvm_vcpu);
#endif
+#if defined(CONFIG_PPC_BOOK3S_32) && defined(CONFIG_PPC_KUAP)
+ OFFSET(KUAP, thread_struct, kuap);
+#endif
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
OFFSET(PACATMSCRATCH, paca_struct, tm_scratch);
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index 46b633514422..d5dc62997267 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -900,6 +900,9 @@ load_up_mmu:
li r0, NUM_USER_SEGMENTS /* load up user segment register values */
mtctr r0 /* for context 0 */
li r3, 0 /* Kp = 0, Ks = 0, VSID = 0 */
+#ifdef CONFIG_PPC_KUAP
+ oris r3, r3, SR_KS@h /* Set Ks */
+#endif
li r4,0
3: mtsrin r3,r4
addi r3,r3,0x111 /* increment VSID */
@@ -907,6 +910,7 @@ load_up_mmu:
bdnz 3b
li r0, 16 - NUM_USER_SEGMENTS /* load up kernel segment registers */
mtctr r0 /* for context 0 */
+ rlwinm r3, r3, 0, ~SR_KS /* Ks = 0 */
oris r3, r3, SR_KP@h /* Kp = 1 */
3: mtsrin r3, r4
addi r3, r3, 0x111 /* increment VSID */
@@ -1015,6 +1019,9 @@ _ENTRY(switch_mmu_context)
blt- 4f
mulli r3,r3,897 /* multiply context by skew factor */
rlwinm r3,r3,4,8,27 /* VSID = (context & 0xfffff) << 4 */
+#ifdef CONFIG_PPC_KUAP
+ oris r3, r3, SR_KS@h /* Set Ks */
+#endif
li r0,NUM_USER_SEGMENTS
mtctr r0
diff --git a/arch/powerpc/mm/ppc_mmu_32.c b/arch/powerpc/mm/ppc_mmu_32.c
index 2d5b0d50fb31..417cf33aa5ba 100644
--- a/arch/powerpc/mm/ppc_mmu_32.c
+++ b/arch/powerpc/mm/ppc_mmu_32.c
@@ -392,3 +392,13 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base,
else /* Anything else has 256M mapped */
memblock_set_current_limit(min_t(u64, first_memblock_size, 0x10000000));
}
+
+#ifdef CONFIG_PPC_KUAP
+void __init setup_kuap(bool disabled)
+{
+ pr_info("Activating Kernel Userspace Access Protection\n");
+
+ if (disabled)
+ pr_warn("KUAP cannot be disabled yet on 6xx when compiled in\n");
+}
+#endif
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index ab586963893a..e3a5cbcc7700 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -25,6 +25,7 @@ config PPC_BOOK3S_32
bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx"
select PPC_FPU
select PPC_HAVE_PMU_SUPPORT
+ select PPC_HAVE_KUAP
config PPC_85xx
bool "Freescale 85xx"
--
2.13.3
^ permalink raw reply related
* [PATCH 6/7] powerpc/book3s32: Prepare Kernel Userspace Access Protection
From: Christophe Leroy @ 2019-03-05 21:18 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1551820474.git.christophe.leroy@c-s.fr>
This patch prepares Kernel Userspace Access Protection for
book3s/32.
Due to limitations of the processor page protection capabilities,
the protection is only against writing. read protection cannot be
achieved using page protection.
book3s/32 provides the following values for PP bits:
PP00 provides RW for Key 0 and NA for Key 1
PP01 provides RW for Key 0 and RO for Key 1
PP10 provides RW for all
PP11 provides RO for all
Today PP10 is used for RW pages and PP11 for RO pages, and user
segment register's Kp and Ks are set to 1. This patch modifies
page protection to use PP01 for RW pages and sets user segment
registers to Kp 0 and Ks 0.
This will allow to setup Userspace write access protection by
settng Ks to 1 in the following patch.
Kernel space segment registers remain unchanged.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/include/asm/book3s/32/mmu-hash.h | 4 ++++
arch/powerpc/kernel/head_32.S | 28 ++++++++++++++++-----------
arch/powerpc/mm/hash_low_32.S | 6 +++---
3 files changed, 24 insertions(+), 14 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/32/mmu-hash.h b/arch/powerpc/include/asm/book3s/32/mmu-hash.h
index 5cb588395fdc..82492dcfa81c 100644
--- a/arch/powerpc/include/asm/book3s/32/mmu-hash.h
+++ b/arch/powerpc/include/asm/book3s/32/mmu-hash.h
@@ -63,6 +63,10 @@ typedef pte_t *pgtable_t;
#define PP_RWRW 2 /* Supervisor read/write, User read/write */
#define PP_RXRX 3 /* Supervisor read, User read */
+/* Values for Segment Registers */
+#define SR_KS 0x40000000 /* Supervisor key */
+#define SR_KP 0x20000000 /* User key */
+
#ifndef __ASSEMBLY__
/*
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index ce6a972f2584..46b633514422 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -522,9 +522,9 @@ InstructionTLBMiss:
andc. r1,r1,r0 /* check access & ~permission */
bne- InstructionAddressInvalid /* return if access not permitted */
/* Convert linux-style PTE to low word of PPC-style PTE */
- rlwimi r0,r0,32-1,30,30 /* _PAGE_USER -> PP msb */
- ori r1, r1, 0xe05 /* clear out reserved bits */
- andc r1, r0, r1 /* PP = user? 2 : 0 */
+ rlwimi r0,r0,32-2,31,31 /* _PAGE_USER -> PP lsb */
+ ori r1, r1, 0xe06 /* clear out reserved bits */
+ andc r1, r0, r1 /* PP = user? 1 : 0 */
BEGIN_FTR_SECTION
rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
@@ -590,11 +590,11 @@ DataLoadTLBMiss:
* we would need to update the pte atomically with lwarx/stwcx.
*/
/* Convert linux-style PTE to low word of PPC-style PTE */
- rlwinm r1,r0,32-10,31,31 /* _PAGE_RW -> PP lsb */
+ rlwinm r1,r0,32-9,30,30 /* _PAGE_RW -> PP msb */
rlwimi r0,r0,32-1,30,30 /* _PAGE_USER -> PP msb */
rlwimi r0,r0,32-1,31,31 /* _PAGE_USER -> PP lsb */
ori r1,r1,0xe04 /* clear out reserved bits */
- andc r1,r0,r1 /* PP = user? rw? 2: 3: 0 */
+ andc r1,r0,r1 /* PP = user? rw? 1: 3: 0 */
BEGIN_FTR_SECTION
rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
@@ -670,9 +670,9 @@ DataStoreTLBMiss:
* we would need to update the pte atomically with lwarx/stwcx.
*/
/* Convert linux-style PTE to low word of PPC-style PTE */
- rlwimi r0,r0,32-1,30,30 /* _PAGE_USER -> PP msb */
- li r1,0xe05 /* clear out reserved bits & PP lsb */
- andc r1,r0,r1 /* PP = user? 2: 0 */
+ rlwimi r0,r0,32-2,31,31 /* _PAGE_USER -> PP lsb */
+ li r1,0xe06 /* clear out reserved bits & PP msb */
+ andc r1,r0,r1 /* PP = user? 1: 0 */
BEGIN_FTR_SECTION
rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */
END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
@@ -897,14 +897,21 @@ load_up_mmu:
tophys(r6,r6)
lwz r6,_SDR1@l(r6)
mtspr SPRN_SDR1,r6
- li r0,16 /* load up segment register values */
+ li r0, NUM_USER_SEGMENTS /* load up user segment register values */
mtctr r0 /* for context 0 */
- lis r3,0x2000 /* Ku = 1, VSID = 0 */
+ li r3, 0 /* Kp = 0, Ks = 0, VSID = 0 */
li r4,0
3: mtsrin r3,r4
addi r3,r3,0x111 /* increment VSID */
addis r4,r4,0x1000 /* address of next segment */
bdnz 3b
+ li r0, 16 - NUM_USER_SEGMENTS /* load up kernel segment registers */
+ mtctr r0 /* for context 0 */
+ oris r3, r3, SR_KP@h /* Kp = 1 */
+3: mtsrin r3, r4
+ addi r3, r3, 0x111 /* increment VSID */
+ addis r4, r4, 0x1000 /* address of next segment */
+ bdnz 3b
/* Load the BAT registers with the values set up by MMU_init.
MMU_init takes care of whether we're on a 601 or not. */
@@ -1008,7 +1015,6 @@ _ENTRY(switch_mmu_context)
blt- 4f
mulli r3,r3,897 /* multiply context by skew factor */
rlwinm r3,r3,4,8,27 /* VSID = (context & 0xfffff) << 4 */
- addis r3,r3,0x6000 /* Set Ks, Ku bits */
li r0,NUM_USER_SEGMENTS
mtctr r0
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S
index 1f13494efb2b..37964878e392 100644
--- a/arch/powerpc/mm/hash_low_32.S
+++ b/arch/powerpc/mm/hash_low_32.S
@@ -309,13 +309,13 @@ Hash_msk = (((1 << Hash_bits) - 1) * 64)
_GLOBAL(create_hpte)
/* Convert linux-style PTE (r5) to low word of PPC-style PTE (r8) */
- rlwinm r8,r5,32-10,31,31 /* _PAGE_RW -> PP lsb */
- rlwinm r0,r5,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */
+ rlwinm r8,r5,32-9,30,30 /* _PAGE_RW -> PP msb */
+ rlwinm r0,r5,32-6,30,30 /* _PAGE_DIRTY -> PP msb */
and r8,r8,r0 /* writable if _RW & _DIRTY */
rlwimi r5,r5,32-1,30,30 /* _PAGE_USER -> PP msb */
rlwimi r5,r5,32-2,31,31 /* _PAGE_USER -> PP lsb */
ori r8,r8,0xe04 /* clear out reserved bits */
- andc r8,r5,r8 /* PP = user? (rw&dirty? 2: 3): 0 */
+ andc r8,r5,r8 /* PP = user? (rw&dirty? 1: 3): 0 */
BEGIN_FTR_SECTION
rlwinm r8,r8,0,~_PAGE_COHERENT /* clear M (coherence not required) */
END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT)
--
2.13.3
^ permalink raw reply related
* [PATCH 4/7] powerpc/32: Prepare for Kernel Userspace Access Protection
From: Christophe Leroy @ 2019-03-05 21:18 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1551820474.git.christophe.leroy@c-s.fr>
This patch adds ASM macros for saving, restoring and checking
the KUAP state, and modifies setup_32 to call them on exceptions
from kernel.
The macros are defined as empty by default for when CONFIG_PPC_KUAP
is not selected and/or for platforms which don't handle (yet) KUAP.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/include/asm/kup.h | 15 ++++++++++++++-
arch/powerpc/kernel/entry_32.S | 16 ++++++++++++----
arch/powerpc/platforms/Kconfig.cputype | 2 +-
3 files changed, 27 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index 082f50ad41a7..51a55be70cbc 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -6,7 +6,20 @@
#include <asm/book3s/64/kup-radix.h>
#endif
-#ifndef __ASSEMBLY__
+#ifdef __ASSEMBLY__
+#ifndef CONFIG_PPC_KUAP
+.macro kuap_save_and_lock sp, thread, gpr1, gpr2, gpr3
+.endm
+
+.macro kuap_restore sp, current, gpr1, gpr2, gpr3
+.endm
+
+.macro kuap_check current, gpr
+.endm
+
+#endif
+
+#else /* !__ASSEMBLY__ */
#include <asm/pgtable.h>
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index b61cfd29c76f..7b7752d6ab2f 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -36,6 +36,7 @@
#include <asm/asm-405.h>
#include <asm/feature-fixups.h>
#include <asm/barrier.h>
+#include <asm/kup.h>
/*
* MSR_KERNEL is > 0x10000 on 4xx/Book-E since it include MSR_CE.
@@ -150,8 +151,8 @@ transfer_to_handler:
stw r12,_CTR(r11)
stw r2,_XER(r11)
mfspr r12,SPRN_SPRG_THREAD
- addi r2,r12,-THREAD
beq 2f /* if from user, fix up THREAD.regs */
+ addi r2, r12, -THREAD
addi r11,r1,STACK_FRAME_OVERHEAD
stw r11,PT_REGS(r12)
#if defined(CONFIG_40x) || defined(CONFIG_BOOKE)
@@ -186,6 +187,8 @@ transfer_to_handler:
2: /* if from kernel, check interrupted DOZE/NAP mode and
* check for stack overflow
*/
+ kuap_save_and_lock r11, r12, r9, r2, r0
+ addi r2, r12, -THREAD
lwz r9,KSP_LIMIT(r12)
cmplw r1,r9 /* if r1 <= ksp_limit */
ble- stack_ovf /* then the kernel stack overflowed */
@@ -272,6 +275,7 @@ reenable_mmu: /* re-enable mmu so we can */
lwz r9,_MSR(r11) /* if sleeping, clear MSR.EE */
rlwinm r9,r9,0,~MSR_EE
lwz r12,_LINK(r11) /* and return to address in LR */
+ kuap_restore r11, r2, r3, r4, r5
b fast_exception_return
#endif
@@ -428,6 +432,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_NEED_PAIRED_STWCX)
ACCOUNT_CPU_USER_EXIT(r2, r5, r7)
3:
#endif
+ kuap_check r2, r4
lwz r4,_LINK(r1)
lwz r5,_CCR(r1)
mtlr r4
@@ -678,6 +683,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_SPE)
stw r10,_CCR(r1)
stw r1,KSP(r3) /* Set old stack pointer */
+ kuap_check r2, r4
#ifdef CONFIG_SMP
/* We need a sync somewhere here to make sure that if the
* previous task gets rescheduled on another CPU, it sees all
@@ -866,12 +872,12 @@ resume_kernel:
/* check current_thread_info->preempt_count */
lwz r0,TI_PREEMPT(r2)
cmpwi 0,r0,0 /* if non-zero, just restore regs and return */
- bne restore
+ bne restore_kuap
andi. r8,r8,_TIF_NEED_RESCHED
- beq+ restore
+ beq+ restore_kuap
lwz r3,_MSR(r1)
andi. r0,r3,MSR_EE /* interrupts off? */
- beq restore /* don't schedule if so */
+ beq restore_kuap /* don't schedule if so */
#ifdef CONFIG_TRACE_IRQFLAGS
/* Lockdep thinks irqs are enabled, we need to call
* preempt_schedule_irq with IRQs off, so we inform lockdep
@@ -890,6 +896,8 @@ resume_kernel:
bl trace_hardirqs_on
#endif
#endif /* CONFIG_PREEMPT */
+restore_kuap:
+ kuap_restore r1, r2, r9, r10, r0
/* interrupts are hard-disabled at this point */
restore:
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 08966e3127bb..00fa0d110dcb 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -374,7 +374,7 @@ config PPC_KUAP
config PPC_KUAP_DEBUG
bool "Extra debugging for Kernel Userspace Access Protection"
- depends on PPC_HAVE_KUAP && PPC_RADIX_MMU
+ depends on PPC_HAVE_KUAP && (PPC_RADIX_MMU || PPC_32)
help
Add extra debugging for Kernel Userspace Access Protection (KUAP)
If you're unsure, say N.
--
2.13.3
^ permalink raw reply related
* [PATCH 0/7] Kernel Userspace protection for PPC32
From: Christophe Leroy @ 2019-03-05 21:18 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
This series intend to implement Kernel Userspace protection for PPC32.
It comes on top of the v4 series for Radix.
Christophe Leroy (6):
powerpc/8xx: Only define APG0 and APG1
powerpc/8xx: Add Kernel Userspace Execution Prevention
powerpc/32: Prepare for Kernel Userspace Access Protection
powerpc/8xx: Add Kernel Userspace Access Protection
powerpc/book3s32: Prepare Kernel Userspace Access Protection
powerpc/book3s32: Implement Kernel Userspace Access Protection
Russell Currey (1):
powerpc/64s: Implement KUAP for Radix MMU (SQUASH)
Documentation/admin-guide/kernel-parameters.txt | 4 +-
arch/powerpc/include/asm/book3s/32/kup.h | 96 +++++++++++++++++++++++++
arch/powerpc/include/asm/book3s/32/mmu-hash.h | 4 ++
arch/powerpc/include/asm/book3s/64/kup-radix.h | 79 ++++++++++++++++++++
arch/powerpc/include/asm/exception-64s.h | 2 +
arch/powerpc/include/asm/feature-fixups.h | 3 +
arch/powerpc/include/asm/futex.h | 4 ++
arch/powerpc/include/asm/kup.h | 72 +++++++++++++++++++
arch/powerpc/include/asm/mmu.h | 10 ++-
arch/powerpc/include/asm/nohash/32/kup-8xx.h | 52 ++++++++++++++
arch/powerpc/include/asm/nohash/32/mmu-8xx.h | 26 +++++--
arch/powerpc/include/asm/processor.h | 3 +
arch/powerpc/include/asm/ptrace.h | 11 ++-
arch/powerpc/include/asm/reg.h | 1 +
arch/powerpc/include/asm/uaccess.h | 38 +++++++---
arch/powerpc/kernel/asm-offsets.c | 7 ++
arch/powerpc/kernel/entry_32.S | 16 +++--
arch/powerpc/kernel/entry_64.S | 22 +++++-
arch/powerpc/kernel/exceptions-64s.S | 3 +
arch/powerpc/kernel/head_32.S | 35 ++++++---
arch/powerpc/kernel/idle_book3s.S | 39 ++++++++++
arch/powerpc/kernel/setup_64.c | 10 +++
arch/powerpc/lib/checksum_wrappers.c | 4 ++
arch/powerpc/lib/code-patching.c | 4 +-
arch/powerpc/mm/8xx_mmu.c | 24 +++++++
arch/powerpc/mm/fault.c | 28 +++++---
arch/powerpc/mm/hash_low_32.S | 6 +-
arch/powerpc/mm/init-common.c | 26 +++++++
arch/powerpc/mm/init_32.c | 3 +
arch/powerpc/mm/pgtable-radix.c | 31 +++++++-
arch/powerpc/mm/pkeys.c | 1 +
arch/powerpc/mm/ppc_mmu_32.c | 10 +++
arch/powerpc/platforms/Kconfig.cputype | 36 ++++++++++
33 files changed, 657 insertions(+), 53 deletions(-)
create mode 100644 arch/powerpc/include/asm/book3s/32/kup.h
create mode 100644 arch/powerpc/include/asm/book3s/64/kup-radix.h
create mode 100644 arch/powerpc/include/asm/kup.h
create mode 100644 arch/powerpc/include/asm/nohash/32/kup-8xx.h
--
2.13.3
^ permalink raw reply
* [PATCH 1/7] powerpc/64s: Implement KUAP for Radix MMU (SQUASH)
From: Christophe Leroy @ 2019-03-05 21:18 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1551820474.git.christophe.leroy@c-s.fr>
Squashed version of the v4 series, not intended to be merged as is.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
Documentation/admin-guide/kernel-parameters.txt | 4 +-
arch/powerpc/include/asm/book3s/64/kup-radix.h | 79 +++++++++++++++++++++++++
arch/powerpc/include/asm/exception-64s.h | 2 +
arch/powerpc/include/asm/feature-fixups.h | 3 +
arch/powerpc/include/asm/futex.h | 4 ++
arch/powerpc/include/asm/kup.h | 53 +++++++++++++++++
arch/powerpc/include/asm/mmu.h | 10 +++-
arch/powerpc/include/asm/ptrace.h | 11 +++-
arch/powerpc/include/asm/reg.h | 1 +
arch/powerpc/include/asm/uaccess.h | 38 +++++++++---
arch/powerpc/kernel/asm-offsets.c | 4 ++
arch/powerpc/kernel/entry_64.S | 22 ++++++-
arch/powerpc/kernel/exceptions-64s.S | 3 +
arch/powerpc/kernel/idle_book3s.S | 39 ++++++++++++
arch/powerpc/kernel/setup_64.c | 10 ++++
arch/powerpc/lib/checksum_wrappers.c | 4 ++
arch/powerpc/lib/code-patching.c | 4 +-
arch/powerpc/mm/fault.c | 28 ++++++---
arch/powerpc/mm/init-common.c | 26 ++++++++
arch/powerpc/mm/init_32.c | 3 +
arch/powerpc/mm/pgtable-radix.c | 31 +++++++++-
arch/powerpc/mm/pkeys.c | 1 +
arch/powerpc/platforms/Kconfig.cputype | 33 +++++++++++
23 files changed, 384 insertions(+), 29 deletions(-)
create mode 100644 arch/powerpc/include/asm/book3s/64/kup-radix.h
create mode 100644 arch/powerpc/include/asm/kup.h
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 858b6c0b9a15..0a76dbb39011 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -2808,11 +2808,11 @@
noexec=on: enable non-executable mappings (default)
noexec=off: disable non-executable mappings
- nosmap [X86]
+ nosmap [X86,PPC]
Disable SMAP (Supervisor Mode Access Prevention)
even if it is supported by processor.
- nosmep [X86]
+ nosmep [X86,PPC]
Disable SMEP (Supervisor Mode Execution Prevention)
even if it is supported by processor.
diff --git a/arch/powerpc/include/asm/book3s/64/kup-radix.h b/arch/powerpc/include/asm/book3s/64/kup-radix.h
new file mode 100644
index 000000000000..87f2af26764c
--- /dev/null
+++ b/arch/powerpc/include/asm/book3s/64/kup-radix.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H
+#define _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H
+
+#ifdef __ASSEMBLY__
+
+.macro kuap_restore_amr gpr
+#ifdef CONFIG_PPC_KUAP
+ BEGIN_MMU_FTR_SECTION_NESTED(67)
+ ld \gpr, STACK_REGS_KUAP(r1)
+ mtspr SPRN_AMR, \gpr
+ END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_RADIX_KUAP, 67)
+#endif
+.endm
+
+.macro kuap_check_amr gpr
+#ifdef CONFIG_PPC_KUAP_DEBUG
+ BEGIN_MMU_FTR_SECTION_NESTED(67)
+ mfspr \gpr, SPRN_AMR
+ sradi \gpr, \gpr, 48
+999: tdnei \gpr, RADIX_AMR_LOCKED@highest
+ EMIT_BUG_ENTRY 999b,__FILE__,__LINE__, \
+ (BUGFLAG_WARNING|BUGFLAG_ONCE)
+ END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_RADIX_KUAP, 67)
+#endif
+.endm
+
+.macro kuap_save_amr_and_lock gpr, msr_pr_cr
+#ifdef CONFIG_PPC_KUAP
+ BEGIN_MMU_FTR_SECTION_NESTED(67)
+ .ifnb \msr_pr_cr
+ bne \msr_pr_cr, 99f
+ .endif
+ mfspr \gpr, SPRN_AMR
+ std \gpr, STACK_REGS_KUAP(r1)
+ li \gpr, (RADIX_AMR_LOCKED)@highest
+ sldi \gpr, \gpr, 48
+ mtspr SPRN_AMR,\gpr
+99:
+ END_MMU_FTR_SECTION_NESTED_IFSET(MMU_FTR_RADIX_KUAP, 67)
+#endif
+.endm
+
+#else /* !__ASSEMBLY__ */
+
+#ifdef CONFIG_PPC_KUAP
+
+#include <asm/reg.h>
+/*
+ * We do have the ability to individually lock/unlock reads and writes rather
+ * than both at once, however it's a significant performance hit due to needing
+ * to do a read-modify-write, which adds a mfspr, which is slow. As a result,
+ * locking/unlocking both at once is preferred.
+ */
+static inline void allow_user_access(void __user *to, const void __user *from,
+ unsigned long size)
+{
+ if (!mmu_has_feature(MMU_FTR_RADIX_KUAP))
+ return;
+
+ mtspr(SPRN_AMR, 0);
+ isync();
+}
+
+static inline void prevent_user_access(void __user *to, const void __user *from,
+ unsigned long size)
+{
+ if (!mmu_has_feature(MMU_FTR_RADIX_KUAP))
+ return;
+
+ mtspr(SPRN_AMR, RADIX_AMR_LOCKED);
+ isync();
+}
+
+#endif /* CONFIG_PPC_KUAP */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_BOOK3S_64_KUP_RADIX_H */
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
index 937bb630093f..df7cbfc45952 100644
--- a/arch/powerpc/include/asm/exception-64s.h
+++ b/arch/powerpc/include/asm/exception-64s.h
@@ -497,6 +497,7 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
RESTORE_CTR(r1, area); \
b bad_stack; \
3: EXCEPTION_PROLOG_COMMON_1(); \
+ kuap_save_amr_and_lock r9, cr0; \
beq 4f; /* if from kernel mode */ \
ACCOUNT_CPU_USER_ENTRY(r13, r9, r10); \
SAVE_PPR(area, r9); \
@@ -691,6 +692,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_CTRL)
*/
#define EXCEPTION_COMMON_NORET_STACK(area, trap, label, hdlr, additions) \
EXCEPTION_PROLOG_COMMON_1(); \
+ kuap_save_amr_and_lock r9; \
EXCEPTION_PROLOG_COMMON_2(area); \
EXCEPTION_PROLOG_COMMON_3(trap); \
/* Volatile regs are potentially clobbered here */ \
diff --git a/arch/powerpc/include/asm/feature-fixups.h b/arch/powerpc/include/asm/feature-fixups.h
index 40a6c9261a6b..f6fc31f8baff 100644
--- a/arch/powerpc/include/asm/feature-fixups.h
+++ b/arch/powerpc/include/asm/feature-fixups.h
@@ -100,6 +100,9 @@ label##5: \
#define END_MMU_FTR_SECTION(msk, val) \
END_MMU_FTR_SECTION_NESTED(msk, val, 97)
+#define END_MMU_FTR_SECTION_NESTED_IFSET(msk, label) \
+ END_MMU_FTR_SECTION_NESTED((msk), (msk), label)
+
#define END_MMU_FTR_SECTION_IFSET(msk) END_MMU_FTR_SECTION((msk), (msk))
#define END_MMU_FTR_SECTION_IFCLR(msk) END_MMU_FTR_SECTION((msk), 0)
diff --git a/arch/powerpc/include/asm/futex.h b/arch/powerpc/include/asm/futex.h
index 88b38b37c21b..3a6aa57b9d90 100644
--- a/arch/powerpc/include/asm/futex.h
+++ b/arch/powerpc/include/asm/futex.h
@@ -35,6 +35,7 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
{
int oldval = 0, ret;
+ allow_write_to_user(uaddr, sizeof(*uaddr));
pagefault_disable();
switch (op) {
@@ -62,6 +63,7 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
if (!ret)
*oval = oldval;
+ prevent_write_to_user(uaddr, sizeof(*uaddr));
return ret;
}
@@ -75,6 +77,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
if (!access_ok(uaddr, sizeof(u32)))
return -EFAULT;
+ allow_write_to_user(uaddr, sizeof(*uaddr));
__asm__ __volatile__ (
PPC_ATOMIC_ENTRY_BARRIER
"1: lwarx %1,0,%3 # futex_atomic_cmpxchg_inatomic\n\
@@ -95,6 +98,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
: "cc", "memory");
*uval = prev;
+ prevent_write_to_user(uaddr, sizeof(*uaddr));
return ret;
}
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
new file mode 100644
index 000000000000..082f50ad41a7
--- /dev/null
+++ b/arch/powerpc/include/asm/kup.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_POWERPC_KUP_H_
+#define _ASM_POWERPC_KUP_H_
+
+#ifdef CONFIG_PPC_BOOK3S_64
+#include <asm/book3s/64/kup-radix.h>
+#endif
+
+#ifndef __ASSEMBLY__
+
+#include <asm/pgtable.h>
+
+void setup_kup(void);
+
+#ifdef CONFIG_PPC_KUEP
+void setup_kuep(bool disabled);
+#else
+static inline void setup_kuep(bool disabled) { }
+#endif /* CONFIG_PPC_KUEP */
+
+#ifdef CONFIG_PPC_KUAP
+void setup_kuap(bool disabled);
+#else
+static inline void setup_kuap(bool disabled) { }
+static inline void allow_user_access(void __user *to, const void __user *from,
+ unsigned long size) { }
+static inline void prevent_user_access(void __user *to, const void __user *from,
+ unsigned long size) { }
+#endif /* CONFIG_PPC_KUAP */
+
+static inline void allow_read_from_user(const void __user *from, unsigned long size)
+{
+ allow_user_access(NULL, from, size);
+}
+
+static inline void allow_write_to_user(void __user *to, unsigned long size)
+{
+ allow_user_access(to, NULL, size);
+}
+
+static inline void prevent_read_from_user(const void __user *from, unsigned long size)
+{
+ prevent_user_access(NULL, from, size);
+}
+
+static inline void prevent_write_to_user(void __user *to, unsigned long size)
+{
+ prevent_user_access(to, NULL, size);
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_POWERPC_KUP_H_ */
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index d34ad1657d7b..59acb4418164 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -107,6 +107,11 @@
*/
#define MMU_FTR_1T_SEGMENT ASM_CONST(0x40000000)
+/*
+ * Supports KUAP (key 0 controlling userspace addresses) on radix
+ */
+#define MMU_FTR_RADIX_KUAP ASM_CONST(0x80000000)
+
/* MMU feature bit sets for various CPUs */
#define MMU_FTRS_DEFAULT_HPTE_ARCH_V2 \
MMU_FTR_HPTE_TABLE | MMU_FTR_PPCAS_ARCH_V2
@@ -164,7 +169,10 @@ enum {
#endif
#ifdef CONFIG_PPC_RADIX_MMU
MMU_FTR_TYPE_RADIX |
-#endif
+#ifdef CONFIG_PPC_KUAP
+ MMU_FTR_RADIX_KUAP |
+#endif /* CONFIG_PPC_KUAP */
+#endif /* CONFIG_PPC_RADIX_MMU */
0,
};
diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h
index 64271e562fed..6f047730e642 100644
--- a/arch/powerpc/include/asm/ptrace.h
+++ b/arch/powerpc/include/asm/ptrace.h
@@ -52,10 +52,17 @@ struct pt_regs
};
};
+ union {
+ struct {
#ifdef CONFIG_PPC64
- unsigned long ppr;
- unsigned long __pad; /* Maintain 16 byte interrupt stack alignment */
+ unsigned long ppr;
+#endif
+#ifdef CONFIG_PPC_KUAP
+ unsigned long kuap;
#endif
+ };
+ unsigned long __pad[2]; /* Maintain 16 byte interrupt stack alignment */
+ };
};
#endif
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index c5b2aff0ce8e..6350873af4bc 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -246,6 +246,7 @@
#define SPRN_DSCR 0x11
#define SPRN_CFAR 0x1c /* Come From Address Register */
#define SPRN_AMR 0x1d /* Authority Mask Register */
+#define RADIX_AMR_LOCKED 0xC000000000000000UL /* Read & Write disabled */
#define SPRN_UAMOR 0x9d /* User Authority Mask Override Register */
#define SPRN_AMOR 0x15d /* Authority Mask Override Register */
#define SPRN_ACOP 0x1F /* Available Coprocessor Register */
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index e3a731793ea2..fb7651a5488b 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -6,6 +6,7 @@
#include <asm/processor.h>
#include <asm/page.h>
#include <asm/extable.h>
+#include <asm/kup.h>
/*
* The fs value determines whether argument validity checking should be
@@ -141,6 +142,7 @@ extern long __put_user_bad(void);
#define __put_user_size(x, ptr, size, retval) \
do { \
retval = 0; \
+ allow_write_to_user(ptr, size); \
switch (size) { \
case 1: __put_user_asm(x, ptr, retval, "stb"); break; \
case 2: __put_user_asm(x, ptr, retval, "sth"); break; \
@@ -148,6 +150,7 @@ do { \
case 8: __put_user_asm2(x, ptr, retval); break; \
default: __put_user_bad(); \
} \
+ prevent_write_to_user(ptr, size); \
} while (0)
#define __put_user_nocheck(x, ptr, size) \
@@ -240,6 +243,7 @@ do { \
__chk_user_ptr(ptr); \
if (size > sizeof(x)) \
(x) = __get_user_bad(); \
+ allow_read_from_user(ptr, size); \
switch (size) { \
case 1: __get_user_asm(x, ptr, retval, "lbz"); break; \
case 2: __get_user_asm(x, ptr, retval, "lhz"); break; \
@@ -247,6 +251,7 @@ do { \
case 8: __get_user_asm2(x, ptr, retval); break; \
default: (x) = __get_user_bad(); \
} \
+ prevent_read_from_user(ptr, size); \
} while (0)
/*
@@ -306,15 +311,21 @@ extern unsigned long __copy_tofrom_user(void __user *to,
static inline unsigned long
raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
{
- return __copy_tofrom_user(to, from, n);
+ unsigned long ret;
+
+ allow_user_access(to, from, n);
+ ret = __copy_tofrom_user(to, from, n);
+ prevent_user_access(to, from, n);
+ return ret;
}
#endif /* __powerpc64__ */
static inline unsigned long raw_copy_from_user(void *to,
const void __user *from, unsigned long n)
{
+ unsigned long ret;
if (__builtin_constant_p(n) && (n <= 8)) {
- unsigned long ret = 1;
+ ret = 1;
switch (n) {
case 1:
@@ -339,14 +350,18 @@ static inline unsigned long raw_copy_from_user(void *to,
}
barrier_nospec();
- return __copy_tofrom_user((__force void __user *)to, from, n);
+ allow_read_from_user(from, n);
+ ret = __copy_tofrom_user((__force void __user *)to, from, n);
+ prevent_read_from_user(from, n);
+ return ret;
}
static inline unsigned long raw_copy_to_user(void __user *to,
const void *from, unsigned long n)
{
+ unsigned long ret;
if (__builtin_constant_p(n) && (n <= 8)) {
- unsigned long ret = 1;
+ ret = 1;
switch (n) {
case 1:
@@ -366,17 +381,24 @@ static inline unsigned long raw_copy_to_user(void __user *to,
return 0;
}
- return __copy_tofrom_user(to, (__force const void __user *)from, n);
+ allow_write_to_user(to, n);
+ ret = __copy_tofrom_user(to, (__force const void __user *)from, n);
+ prevent_write_to_user(to, n);
+ return ret;
}
extern unsigned long __clear_user(void __user *addr, unsigned long size);
static inline unsigned long clear_user(void __user *addr, unsigned long size)
{
+ unsigned long ret = size;
might_fault();
- if (likely(access_ok(addr, size)))
- return __clear_user(addr, size);
- return size;
+ if (likely(access_ok(addr, size))) {
+ allow_write_to_user(addr, size);
+ ret = __clear_user(addr, size);
+ prevent_write_to_user(addr, size);
+ }
+ return ret;
}
extern long strncpy_from_user(char *dst, const char __user *src, long count);
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 86a61e5f8285..66202e02fee2 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -332,6 +332,10 @@ int main(void)
STACK_PT_REGS_OFFSET(_PPR, ppr);
#endif /* CONFIG_PPC64 */
+#ifdef CONFIG_PPC_KUAP
+ STACK_PT_REGS_OFFSET(STACK_REGS_KUAP, kuap);
+#endif
+
#if defined(CONFIG_PPC32)
#if defined(CONFIG_BOOKE) || defined(CONFIG_40x)
DEFINE(EXC_LVL_SIZE, STACK_EXC_LVL_FRAME_SIZE);
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 15c67d2c0534..612cfa4bffd7 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -46,6 +46,7 @@
#include <asm/exception-64e.h>
#endif
#include <asm/feature-fixups.h>
+#include <asm/kup.h>
/*
* System calls.
@@ -275,6 +276,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS)
andi. r6,r8,MSR_PR
ld r4,_LINK(r1)
+ kuap_check_amr r11
+
#ifdef CONFIG_PPC_BOOK3S
/*
* Clear MSR_RI, MSR_EE is already and remains disabled. We could do
@@ -296,6 +299,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
std r8, PACATMSCRATCH(r13)
#endif
+ /*
+ * We don't need to restore AMR on the way back to userspace for KUAP.
+ * The value of AMR only matters while we're in the kernel.
+ */
ld r13,GPR13(r1) /* only restore r13 if returning to usermode */
ld r2,GPR2(r1)
ld r1,GPR1(r1)
@@ -306,8 +313,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
RFI_TO_USER
b . /* prevent speculative execution */
- /* exit to kernel */
-1: ld r2,GPR2(r1)
+1: /* exit to kernel */
+ kuap_restore_amr r2
+
+ ld r2,GPR2(r1)
ld r1,GPR1(r1)
mtlr r4
mtcr r5
@@ -594,6 +603,8 @@ _GLOBAL(_switch)
std r23,_CCR(r1)
std r1,KSP(r3) /* Set old stack pointer */
+ kuap_check_amr r6
+
FLUSH_COUNT_CACHE
/*
@@ -974,6 +985,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
ACCOUNT_CPU_USER_EXIT(r13, r2, r4)
REST_GPR(13, r1)
+ /*
+ * We don't need to restore AMR on the way back to userspace for KUAP.
+ * The value of AMR only matters while we're in the kernel.
+ */
mtspr SPRN_SRR1,r3
ld r2,_CCR(r1)
@@ -1006,6 +1021,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
ld r0,GPR0(r1)
ld r2,GPR2(r1)
ld r3,GPR3(r1)
+
+ kuap_restore_amr r4
+
ld r4,GPR4(r1)
ld r1,GPR1(r1)
RFI_TO_KERNEL
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index a5b8fbae56a0..dd73f4ae6cb7 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -19,6 +19,7 @@
#include <asm/cpuidle.h>
#include <asm/head-64.h>
#include <asm/feature-fixups.h>
+#include <asm/kup.h>
/*
* There are a few constraints to be concerned with.
@@ -309,6 +310,7 @@ TRAMP_REAL_BEGIN(machine_check_common_early)
mfspr r11,SPRN_DSISR /* Save DSISR */
std r11,_DSISR(r1)
std r9,_CCR(r1) /* Save CR in stackframe */
+ kuap_save_amr_and_lock r9
/* Save r9 through r13 from EXMC save area to stack frame. */
EXCEPTION_PROLOG_COMMON_2(PACA_EXMC)
mfmsr r11 /* get MSR value */
@@ -1097,6 +1099,7 @@ TRAMP_REAL_BEGIN(hmi_exception_early)
mfspr r11,SPRN_HSRR0 /* Save HSRR0 */
mfspr r12,SPRN_HSRR1 /* Save HSRR1 */
EXCEPTION_PROLOG_COMMON_1()
+ kuap_save_amr_and_lock r9
EXCEPTION_PROLOG_COMMON_2(PACA_EXGEN)
EXCEPTION_PROLOG_COMMON_3(0xe60)
addi r3,r1,STACK_FRAME_OVERHEAD
diff --git a/arch/powerpc/kernel/idle_book3s.S b/arch/powerpc/kernel/idle_book3s.S
index 7f5ac2e8581b..4a860d3b9229 100644
--- a/arch/powerpc/kernel/idle_book3s.S
+++ b/arch/powerpc/kernel/idle_book3s.S
@@ -170,6 +170,12 @@ core_idle_lock_held:
bne- core_idle_lock_held
blr
+/* Reuse some unused pt_regs slots for AMR/IAMR/UAMOR/UAMOR */
+#define PNV_POWERSAVE_AMR _TRAP
+#define PNV_POWERSAVE_IAMR _DAR
+#define PNV_POWERSAVE_UAMOR _DSISR
+#define PNV_POWERSAVE_AMOR RESULT
+
/*
* Pass requested state in r3:
* r3 - PNV_THREAD_NAP/SLEEP/WINKLE in POWER8
@@ -200,6 +206,20 @@ pnv_powersave_common:
/* Continue saving state */
SAVE_GPR(2, r1)
SAVE_NVGPRS(r1)
+
+BEGIN_FTR_SECTION
+ mfspr r4, SPRN_AMR
+ mfspr r5, SPRN_IAMR
+ mfspr r6, SPRN_UAMOR
+ std r4, PNV_POWERSAVE_AMR(r1)
+ std r5, PNV_POWERSAVE_IAMR(r1)
+ std r6, PNV_POWERSAVE_UAMOR(r1)
+BEGIN_FTR_SECTION_NESTED(42)
+ mfspr r7, SPRN_AMOR
+ std r7, PNV_POWERSAVE_AMOR(r1)
+END_FTR_SECTION_NESTED_IFSET(CPU_FTR_HVMODE, 42)
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+
mfcr r5
std r5,_CCR(r1)
std r1,PACAR1(r13)
@@ -924,6 +944,25 @@ BEGIN_FTR_SECTION
END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
REST_NVGPRS(r1)
REST_GPR(2, r1)
+
+BEGIN_FTR_SECTION
+ /* These regs were saved in pnv_powersave_common() */
+ ld r4, PNV_POWERSAVE_AMR(r1)
+ ld r5, PNV_POWERSAVE_IAMR(r1)
+ ld r6, PNV_POWERSAVE_UAMOR(r1)
+ mtspr SPRN_AMR, r4
+ mtspr SPRN_IAMR, r5
+ mtspr SPRN_UAMOR, r6
+BEGIN_FTR_SECTION_NESTED(42)
+ ld r7, PNV_POWERSAVE_AMOR(r1)
+ mtspr SPRN_AMOR, r7
+END_FTR_SECTION_NESTED_IFSET(CPU_FTR_HVMODE, 42)
+ /*
+ * We don't need an isync here after restoring IAMR because the upcoming
+ * mtmsrd is execution synchronizing.
+ */
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+
ld r4,PACAKMSR(r13)
ld r5,_LINK(r1)
ld r6,_CCR(r1)
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index daa361fc6a24..72358a5022fe 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -68,6 +68,7 @@
#include <asm/cputhreads.h>
#include <asm/hw_irq.h>
#include <asm/feature-fixups.h>
+#include <asm/kup.h>
#include "setup.h"
@@ -331,6 +332,12 @@ void __init early_setup(unsigned long dt_ptr)
*/
configure_exceptions();
+ /*
+ * Configure Kernel Userspace Protection. This needs to happen before
+ * feature fixups for platforms that implement this using features.
+ */
+ setup_kup();
+
/* Apply all the dynamic patching */
apply_feature_fixups();
setup_feature_keys();
@@ -383,6 +390,9 @@ void early_setup_secondary(void)
/* Initialize the hash table or TLB handling */
early_init_mmu_secondary();
+ /* Perform any KUP setup that is per-cpu */
+ setup_kup();
+
/*
* At this point, we can let interrupts switch to virtual mode
* (the MMU has been setup), so adjust the MSR in the PACA to
diff --git a/arch/powerpc/lib/checksum_wrappers.c b/arch/powerpc/lib/checksum_wrappers.c
index 890d4ddd91d6..bb9307ce2440 100644
--- a/arch/powerpc/lib/checksum_wrappers.c
+++ b/arch/powerpc/lib/checksum_wrappers.c
@@ -29,6 +29,7 @@ __wsum csum_and_copy_from_user(const void __user *src, void *dst,
unsigned int csum;
might_sleep();
+ allow_read_from_user(src, len);
*err_ptr = 0;
@@ -60,6 +61,7 @@ __wsum csum_and_copy_from_user(const void __user *src, void *dst,
}
out:
+ prevent_read_from_user(src, len);
return (__force __wsum)csum;
}
EXPORT_SYMBOL(csum_and_copy_from_user);
@@ -70,6 +72,7 @@ __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,
unsigned int csum;
might_sleep();
+ allow_write_to_user(dst, len);
*err_ptr = 0;
@@ -97,6 +100,7 @@ __wsum csum_and_copy_to_user(const void *src, void __user *dst, int len,
}
out:
+ prevent_write_to_user(dst, len);
return (__force __wsum)csum;
}
EXPORT_SYMBOL(csum_and_copy_to_user);
diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c
index 506413a2c25e..42fdadac6587 100644
--- a/arch/powerpc/lib/code-patching.c
+++ b/arch/powerpc/lib/code-patching.c
@@ -26,9 +26,9 @@
static int __patch_instruction(unsigned int *exec_addr, unsigned int instr,
unsigned int *patch_addr)
{
- int err;
+ int err = 0;
- __put_user_size(instr, patch_addr, 4, err);
+ __put_user_asm(instr, patch_addr, err, "stw");
if (err)
return err;
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 887f11bcf330..463d1e9d026e 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -223,19 +223,28 @@ static int mm_fault_error(struct pt_regs *regs, unsigned long addr,
}
/* Is this a bad kernel fault ? */
-static bool bad_kernel_fault(bool is_exec, unsigned long error_code,
+static bool bad_kernel_fault(struct pt_regs *regs, unsigned long error_code,
unsigned long address)
{
+ int is_exec = TRAP(regs) == 0x400;
+
/* NX faults set DSISR_PROTFAULT on the 8xx, DSISR_NOEXEC_OR_G on others */
if (is_exec && (error_code & (DSISR_NOEXEC_OR_G | DSISR_KEYFAULT |
DSISR_PROTFAULT))) {
- printk_ratelimited(KERN_CRIT "kernel tried to execute"
- " exec-protected page (%lx) -"
- "exploit attempt? (uid: %d)\n",
- address, from_kuid(&init_user_ns,
- current_uid()));
+ pr_crit_ratelimited("kernel tried to execute %s page (%lx) - exploit attempt? (uid: %d)\n",
+ address >= TASK_SIZE ? "exec-protected" : "user",
+ address,
+ from_kuid(&init_user_ns, current_uid()));
+ }
+
+ if (!is_exec && address < TASK_SIZE && (error_code & DSISR_PROTFAULT) &&
+ !search_exception_tables(regs->nip)) {
+ pr_crit_ratelimited("Kernel attempted to access user page (%lx) - exploit attempt? (uid: %d)\n",
+ address,
+ from_kuid(&init_user_ns, current_uid()));
}
- return is_exec || (address >= TASK_SIZE);
+
+ return is_exec || (address >= TASK_SIZE) || !search_exception_tables(regs->nip);
}
static bool bad_stack_expansion(struct pt_regs *regs, unsigned long address,
@@ -455,9 +464,10 @@ static int __do_page_fault(struct pt_regs *regs, unsigned long address,
/*
* The kernel should never take an execute fault nor should it
- * take a page fault to a kernel address.
+ * take a page fault to a kernel address or a page fault to a user
+ * address outside of dedicated places
*/
- if (unlikely(!is_user && bad_kernel_fault(is_exec, error_code, address)))
+ if (unlikely(!is_user && bad_kernel_fault(regs, error_code, address)))
return SIGSEGV;
/*
diff --git a/arch/powerpc/mm/init-common.c b/arch/powerpc/mm/init-common.c
index 1e6910eb70ed..ecaedfff9992 100644
--- a/arch/powerpc/mm/init-common.c
+++ b/arch/powerpc/mm/init-common.c
@@ -24,6 +24,32 @@
#include <linux/string.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
+#include <asm/kup.h>
+
+static bool disable_kuep = !IS_ENABLED(CONFIG_PPC_KUEP);
+static bool disable_kuap = !IS_ENABLED(CONFIG_PPC_KUAP);
+
+static int __init parse_nosmep(char *p)
+{
+ disable_kuep = true;
+ pr_warn("Disabling Kernel Userspace Execution Prevention\n");
+ return 0;
+}
+early_param("nosmep", parse_nosmep);
+
+static int __init parse_nosmap(char *p)
+{
+ disable_kuap = true;
+ pr_warn("Disabling Kernel Userspace Access Protection\n");
+ return 0;
+}
+early_param("nosmap", parse_nosmap);
+
+void __init setup_kup(void)
+{
+ setup_kuep(disable_kuep);
+ setup_kuap(disable_kuap);
+}
#define CTOR(shift) static void ctor_##shift(void *addr) \
{ \
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 41a3513cadc9..80cc97cd8878 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -45,6 +45,7 @@
#include <asm/tlb.h>
#include <asm/sections.h>
#include <asm/hugetlb.h>
+#include <asm/kup.h>
#include "mmu_decl.h"
@@ -178,6 +179,8 @@ void __init MMU_init(void)
btext_unmap();
#endif
+ setup_kup();
+
/* Shortly after that, the entire linear mapping will be available */
memblock_set_current_limit(lowmem_end_addr);
}
diff --git a/arch/powerpc/mm/pgtable-radix.c b/arch/powerpc/mm/pgtable-radix.c
index 931156069a81..aa7d9de3ba3f 100644
--- a/arch/powerpc/mm/pgtable-radix.c
+++ b/arch/powerpc/mm/pgtable-radix.c
@@ -29,6 +29,7 @@
#include <asm/powernv.h>
#include <asm/sections.h>
#include <asm/trace.h>
+#include <asm/uaccess.h>
#include <trace/events/thp.h>
@@ -535,8 +536,15 @@ static void radix_init_amor(void)
mtspr(SPRN_AMOR, (3ul << 62));
}
-static void radix_init_iamr(void)
+#ifdef CONFIG_PPC_KUEP
+void __init setup_kuep(bool disabled)
{
+ if (disabled || !early_radix_enabled())
+ return;
+
+ if (smp_processor_id() == boot_cpuid)
+ pr_info("Activating Kernel Userspace Execution Prevention\n");
+
/*
* Radix always uses key0 of the IAMR to determine if an access is
* allowed. We set bit 0 (IBM bit 1) of key0, to prevent instruction
@@ -544,6 +552,25 @@ static void radix_init_iamr(void)
*/
mtspr(SPRN_IAMR, (1ul << 62));
}
+#endif
+
+#ifdef CONFIG_PPC_KUAP
+void __init setup_kuap(bool disabled)
+{
+ if (disabled || !early_radix_enabled())
+ return;
+
+ if (smp_processor_id() == boot_cpuid) {
+ pr_info("Activating Kernel Userspace Access Prevention\n");
+ cur_cpu_spec->mmu_features |= MMU_FTR_RADIX_KUAP;
+ }
+
+ /* Make sure userspace can't change the AMR */
+ mtspr(SPRN_UAMOR, 0);
+
+ mtspr(SPRN_AMR, RADIX_AMR_LOCKED);
+}
+#endif
void __init radix__early_init_mmu(void)
{
@@ -605,7 +632,6 @@ void __init radix__early_init_mmu(void)
memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
- radix_init_iamr();
radix_init_pgtable();
/* Switch to the guard PID before turning on MMU */
radix__switch_mmu_context(NULL, &init_mm);
@@ -627,7 +653,6 @@ void radix__early_init_mmu_secondary(void)
__pa(partition_tb) | (PATB_SIZE_SHIFT - 12));
radix_init_amor();
}
- radix_init_iamr();
radix__switch_mmu_context(NULL, &init_mm);
if (cpu_has_feature(CPU_FTR_HVMODE))
diff --git a/arch/powerpc/mm/pkeys.c b/arch/powerpc/mm/pkeys.c
index 587807763737..ae7fca40e5b3 100644
--- a/arch/powerpc/mm/pkeys.c
+++ b/arch/powerpc/mm/pkeys.c
@@ -7,6 +7,7 @@
#include <asm/mman.h>
#include <asm/mmu_context.h>
+#include <asm/mmu.h>
#include <asm/setup.h>
#include <linux/pkeys.h>
#include <linux/of_device.h>
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 842b2c7e156a..5e53b9fd62aa 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -326,6 +326,8 @@ config PPC_RADIX_MMU
bool "Radix MMU Support"
depends on PPC_BOOK3S_64
select ARCH_HAS_GIGANTIC_PAGE if (MEMORY_ISOLATION && COMPACTION) || CMA
+ select PPC_HAVE_KUEP
+ select PPC_HAVE_KUAP
default y
help
Enable support for the Power ISA 3.0 Radix style MMU. Currently this
@@ -345,6 +347,37 @@ config PPC_RADIX_MMU_DEFAULT
If you're unsure, say Y.
+config PPC_HAVE_KUEP
+ bool
+
+config PPC_KUEP
+ bool "Kernel Userspace Execution Prevention"
+ depends on PPC_HAVE_KUEP
+ default y
+ help
+ Enable support for Kernel Userspace Execution Prevention (KUEP)
+
+ If you're unsure, say Y.
+
+config PPC_HAVE_KUAP
+ bool
+
+config PPC_KUAP
+ bool "Kernel Userspace Access Protection"
+ depends on PPC_HAVE_KUAP
+ default y
+ help
+ Enable support for Kernel Userspace Access Protection (KUAP)
+
+ If you're unsure, say Y.
+
+config PPC_KUAP_DEBUG
+ bool "Extra debugging for Kernel Userspace Access Protection"
+ depends on PPC_HAVE_KUAP && PPC_RADIX_MMU
+ help
+ Add extra debugging for Kernel Userspace Access Protection (KUAP)
+ If you're unsure, say N.
+
config ARCH_ENABLE_HUGEPAGE_MIGRATION
def_bool y
depends on PPC_BOOK3S_64 && HUGETLB_PAGE && MIGRATION
--
2.13.3
^ permalink raw reply related
* [PATCH 3/7] powerpc/8xx: Add Kernel Userspace Execution Prevention
From: Christophe Leroy @ 2019-03-05 21:18 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1551820474.git.christophe.leroy@c-s.fr>
This patch adds Kernel Userspace Execution Prevention on the 8xx.
When a page is Executable, it is set Executable for Key 0 and NX
for Key 1.
Up to now, the User group is defined with Key 0 for both User and
Supervisor.
By changing the group to Key 0 for User and Key 1 for Supervisor,
this patch prevents the Kernel from being able to execute user code.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/include/asm/nohash/32/mmu-8xx.h | 7 +++++++
arch/powerpc/mm/8xx_mmu.c | 12 ++++++++++++
arch/powerpc/platforms/Kconfig.cputype | 1 +
3 files changed, 20 insertions(+)
diff --git a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
index fc5a653d5dd2..3cb743284e09 100644
--- a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
@@ -41,6 +41,13 @@
*/
#define MI_APG_INIT 0x4fffffff
+/*
+ * 0 => Kernel => 01 (all accesses performed according to page definition)
+ * 1 => User => 10 (all accesses performed according to swaped page definition)
+ * 2-16 => NA => 11 (all accesses performed as user iaw page definition)
+ */
+#define MI_APG_KUEP 0x6fffffff
+
/* The effective page number register. When read, contains the information
* about the last instruction TLB miss. When MI_RPN is written, bits in
* this register are used to create the TLB entry.
diff --git a/arch/powerpc/mm/8xx_mmu.c b/arch/powerpc/mm/8xx_mmu.c
index fe1f6443d57f..e257a0c9bd08 100644
--- a/arch/powerpc/mm/8xx_mmu.c
+++ b/arch/powerpc/mm/8xx_mmu.c
@@ -213,3 +213,15 @@ void flush_instruction_cache(void)
mtspr(SPRN_IC_CST, IDC_INVALL);
isync();
}
+
+#ifdef CONFIG_PPC_KUEP
+void __init setup_kuep(bool disabled)
+{
+ if (disabled)
+ return;
+
+ pr_info("Activating Kernel Userspace Execution Prevention\n");
+
+ mtspr(SPRN_MI_AP, MI_APG_KUEP);
+}
+#endif
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 5e53b9fd62aa..08966e3127bb 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -34,6 +34,7 @@ config PPC_8xx
bool "Freescale 8xx"
select FSL_SOC
select SYS_SUPPORTS_HUGETLBFS
+ select PPC_HAVE_KUEP
config 40x
bool "AMCC 40x"
--
2.13.3
^ permalink raw reply related
* [PATCH 2/7] powerpc/8xx: Only define APG0 and APG1
From: Christophe Leroy @ 2019-03-05 21:18 UTC (permalink / raw)
To: Benjamin Herrenschmidt, Paul Mackerras, Michael Ellerman, ruscur
Cc: linuxppc-dev, linux-kernel
In-Reply-To: <cover.1551820474.git.christophe.leroy@c-s.fr>
Since the 8xx implements hardware page table walk assistance,
the PGD entries always point to a 4k aligned page, so the 2 upper
bit of the APG are not clobbered anymore and remain 0. Therefore
only APG0 and APG1 are used and need a definition. We set the
other APG to the lowest permission level.
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
---
arch/powerpc/include/asm/nohash/32/mmu-8xx.h | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
index 0a1a3fc54e54..fc5a653d5dd2 100644
--- a/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/mmu-8xx.h
@@ -35,11 +35,11 @@
* Then we use the APG to say whether accesses are according to Page rules or
* "all Supervisor" rules (Access to all)
* Therefore, we define 2 APG groups. lsb is _PMD_USER
- * 0 => No user => 01 (all accesses performed according to page definition)
+ * 0 => Kernel => 01 (all accesses performed according to page definition)
* 1 => User => 00 (all accesses performed as supervisor iaw page definition)
- * We define all 16 groups so that all other bits of APG can take any value
+ * 2-16 => NA => 11 (all accesses performed as user iaw page definition)
*/
-#define MI_APG_INIT 0x44444444
+#define MI_APG_INIT 0x4fffffff
/* The effective page number register. When read, contains the information
* about the last instruction TLB miss. When MI_RPN is written, bits in
@@ -108,11 +108,11 @@
* Then we use the APG to say whether accesses are according to Page rules or
* "all Supervisor" rules (Access to all)
* Therefore, we define 2 APG groups. lsb is _PMD_USER
- * 0 => No user => 01 (all accesses performed according to page definition)
+ * 0 => Kernel => 01 (all accesses performed according to page definition)
* 1 => User => 00 (all accesses performed as supervisor iaw page definition)
- * We define all 16 groups so that all other bits of APG can take any value
+ * 2-16 => NA => 11 (all accesses performed as user iaw page definition)
*/
-#define MD_APG_INIT 0x44444444
+#define MD_APG_INIT 0x4fffffff
/* The effective page number register. When read, contains the information
* about the last instruction TLB miss. When MD_RPN is written, bits in
--
2.13.3
^ permalink raw reply related
* Re: [PATCH RFC v4 3/9] powerpc/pci: Create pci_dn on demand
From: Sergey Miroshnichenko @ 2019-03-05 16:50 UTC (permalink / raw)
To: Oliver; +Cc: Stewart Smith, Alexey Kardashevskiy, linux, linuxppc-dev
In-Reply-To: <CAOSf1CGZcy3N5-KztkakNSDD5w4kg5CL4ucMMbWyYxd=eEa5dw@mail.gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 7784 bytes --]
On 3/5/19 11:04 AM, Oliver wrote:
> On Sat, Mar 2, 2019 at 3:04 AM Sergey Miroshnichenko
> <s.miroshnichenko@yadro.com> wrote:
>>
>> If a struct pci_dn hasn't yet been created for the PCIe device (there was
>> no DT node for it), allocate this structure and fill with info read from
>> the device directly.
>>
>> Signed-off-by: Sergey Miroshnichenko <s.miroshnichenko@yadro.com>
>> ---
>> arch/powerpc/kernel/pci_dn.c | 79 ++++++++++++++++++++++++++++++++----
>> 1 file changed, 72 insertions(+), 7 deletions(-)
>>
>> diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
>> index 341ed71250f1..67ccd7be8344 100644
>> --- a/arch/powerpc/kernel/pci_dn.c
>> +++ b/arch/powerpc/kernel/pci_dn.c
>> @@ -33,6 +33,8 @@
>> #include <asm/firmware.h>
>> #include <asm/eeh.h>
>>
>> +static struct pci_dn *create_pdn(struct pci_dev *pdev, struct pci_dn *parent);
>> +
>> /*
>> * The function is used to find the firmware data of one
>> * specific PCI device, which is attached to the indicated
>> @@ -65,6 +67,9 @@ struct pci_dn *pci_bus_to_pdn(struct pci_bus *bus)
>> dn = pci_bus_to_OF_node(pbus);
>> pdn = dn ? PCI_DN(dn) : NULL;
>>
>> + if (!pdn && pbus->self)
>> + pdn = pbus->self->dev.archdata.pci_data;
>> +
>> return pdn;
>> }
>>
>> @@ -74,10 +79,13 @@ struct pci_dn *pci_get_pdn_by_devfn(struct pci_bus *bus,
>> struct device_node *dn = NULL;
>> struct pci_dn *parent, *pdn;
>> struct pci_dev *pdev = NULL;
>> + bool pdev_found = false;
>>
>> /* Fast path: fetch from PCI device */
>> list_for_each_entry(pdev, &bus->devices, bus_list) {
>> if (pdev->devfn == devfn) {
>> + pdev_found = true;
>> +
>> if (pdev->dev.archdata.pci_data)
>> return pdev->dev.archdata.pci_data;
>>
>> @@ -86,6 +94,9 @@ struct pci_dn *pci_get_pdn_by_devfn(struct pci_bus *bus,
>> }
>> }
>>
>> + if (!pdev_found)
>> + pdev = NULL;
>> +
>> /* Fast path: fetch from device node */
>> pdn = dn ? PCI_DN(dn) : NULL;
>> if (pdn)
>> @@ -98,9 +109,12 @@ struct pci_dn *pci_get_pdn_by_devfn(struct pci_bus *bus,
>>
>> list_for_each_entry(pdn, &parent->child_list, list) {
>> if (pdn->busno == bus->number &&
>> - pdn->devfn == devfn)
>> - return pdn;
>> - }
>> + pdn->devfn == devfn) {
>> + if (pdev)
>> + pdev->dev.archdata.pci_data = pdn;
>> + return pdn;
>> + }
>> + }
>>
>> return NULL;
>> }
>> @@ -130,14 +144,15 @@ struct pci_dn *pci_get_pdn(struct pci_dev *pdev)
>>
>> list_for_each_entry(pdn, &parent->child_list, list) {
>> if (pdn->busno == pdev->bus->number &&
>> - pdn->devfn == pdev->devfn)
>> + pdn->devfn == pdev->devfn) {
>> + pdev->dev.archdata.pci_data = pdn;
>> return pdn;
>> + }
>> }
>>
>> - return NULL;
>> + return create_pdn(pdev, parent);
>> }
>
> Eh... If it works I guess it's fine? Killing pdn entirely (or at the
> very least greatly restricting it's role) is something we should work
> towards though since it doesn't make much sense on PNV.
>
As I can see, pdns are mostly used on PNV for the following:
- storing a pe_number;
- storing struct resource holes - to reserve memory for SR-IOV;
- IOMMU table_group;
- storing m64_map;
- storing struct eeh_dev *edev;
Other fields (busno, devfn, etc.) are available in struct pci_dev.
The pe_numbers are probably can be somehow moved to struct pnv_phb, and
they can be fetched from there by a bdfn. The same for other used
fields. Or there could some new structure - shorter version of struct
pci_dn, without .child_list etc.
Thanks for the review, all the issues you've pointed below will be fixed
in v5!
Best regards,
Serge
>> -#ifdef CONFIG_PCI_IOV
>> static struct pci_dn *add_one_dev_pci_data(struct pci_dn *parent,
>> int vf_index,
>> int busno, int devfn)
>> @@ -156,7 +171,9 @@ static struct pci_dn *add_one_dev_pci_data(struct pci_dn *parent,
>> pdn->parent = parent;
>> pdn->busno = busno;
>> pdn->devfn = devfn;
>> + #ifdef CONFIG_PCI_IOV
>> pdn->vf_index = vf_index;
>> + #endif /* CONFIG_PCI_IOV */
>
> This function is currently only used when adding VFs, so I'd move the
> VF specific params from this and put them in the call site at
> add_dev_pci_data(). Then you can drop the #ifdef hacks. It might be
> worth renaming add_one_dev_pci_data() and add_one_dev_pci_data() since
> their actual usage is limited to the VF init path, but their name seem
> generic.
>
>> pdn->pe_number = IODA_INVALID_PE;
>> INIT_LIST_HEAD(&pdn->child_list);
>> INIT_LIST_HEAD(&pdn->list);
>> @@ -164,7 +181,55 @@ static struct pci_dn *add_one_dev_pci_data(struct pci_dn *parent,
>>
>> return pdn;
>> }
>> -#endif
>> +
>> +static struct pci_dn *create_pdn(struct pci_dev *pdev, struct pci_dn *parent)
>> +{
>> + struct pci_dn *pdn = NULL;
>> +
>> + if (!parent)
>> + return NULL;
>> +
>> + pdn = add_one_dev_pci_data(parent, 0, pdev->bus->busn_res.start, pdev->devfn);
>> + dev_info(&pdev->dev, "Create a new pdn for devfn %2x\n", pdev->devfn / 8);
>> +
>
>> + if (pdn) {
>
> Check for !pdn and exit early. Stacking indentation levels just gets
> kind of ugly.
>
>> + #ifdef CONFIG_EEH
>> + struct eeh_dev *edev;
>> + #endif /* CONFIG_EEH */
> You don't use the variable for anything. You can either switch this to
> a void pointer or just check the return value of eeh_dev_init()
> directly and drop this.
>
>> + u32 class_code;
>> + u16 device_id;
>> + u16 vendor_id;
>> +
>
>> + #ifdef CONFIG_EEH
>> + edev = eeh_dev_init(pdn);
>> + if (!edev) {
>> + kfree(pdn);
>> + dev_err(&pdev->dev, "%s: Failed to allocate edev\n", __func__);
>> + return NULL;
>> + }
>> + #endif /* CONFIG_EEH */
>> +
>> + pci_bus_read_config_word(pdev->bus, pdev->devfn,
>> + PCI_VENDOR_ID, &vendor_id);
>> + pdn->vendor_id = vendor_id;
>> +
>> + pci_bus_read_config_word(pdev->bus, pdev->devfn,
>> + PCI_DEVICE_ID, &device_id);
>> + pdn->device_id = device_id;
>> +
>> + pci_bus_read_config_dword(pdev->bus, pdev->devfn,
>> + PCI_CLASS_REVISION, &class_code);
>> + class_code >>= 8;
>> + pdn->class_code = class_code;
>> +
>> + pdn->pci_ext_config_space = 0;
> Does this need to be explicitly initialised or can we rely on it being
> allocated with kzalloc() or similar?
>
>> + pdev->dev.archdata.pci_data = pdn;
>> + } else {
>> + dev_err(&pdev->dev, "%s: Failed to allocate pdn\n", __func__);
>> + }
>> +
>> + return pdn;
>> +}
>>
>> struct pci_dn *add_dev_pci_data(struct pci_dev *pdev)
>> {
>> --
>> 2.20.1
>>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH RFC v4 2/9] powerpc/powernv/pci: Suppress an EEH error when reading an empty slot
From: Sergey Miroshnichenko @ 2019-03-05 15:13 UTC (permalink / raw)
To: Oliver; +Cc: Stewart Smith, Alexey Kardashevskiy, linux, linuxppc-dev
In-Reply-To: <CAOSf1CG0c_4jZQKanq7WHo-n9Urmx8NG8yVWbbx07ivZDu9e-A@mail.gmail.com>
[-- Attachment #1.1: Type: text/plain, Size: 4788 bytes --]
On 3/5/19 9:14 AM, Oliver wrote:
> On Sat, Mar 2, 2019 at 3:04 AM Sergey Miroshnichenko
> <s.miroshnichenko@yadro.com> wrote:
>>
>> Reading an empty slot returns all ones, which triggers a false
>> EEH error event on PowerNV. This patch unfreezes the bus where
>> it has happened.
>>
>> Signed-off-by: Sergey Miroshnichenko <s.miroshnichenko@yadro.com>
>> ---
>> arch/powerpc/include/asm/ppc-pci.h | 1 +
>> arch/powerpc/kernel/pci_dn.c | 2 +-
>> arch/powerpc/platforms/powernv/pci.c | 34 ++++++++++++++++++++++++----
>> 3 files changed, 32 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h
>> index f67da277d652..737393c54f58 100644
>> --- a/arch/powerpc/include/asm/ppc-pci.h
>> +++ b/arch/powerpc/include/asm/ppc-pci.h
>> @@ -40,6 +40,7 @@ void *traverse_pci_dn(struct pci_dn *root,
>> void *(*fn)(struct pci_dn *, void *),
>> void *data);
>> extern void pci_devs_phb_init_dynamic(struct pci_controller *phb);
>> +struct pci_dn *pci_bus_to_pdn(struct pci_bus *bus);
>>
>> /* From rtas_pci.h */
>> extern void init_pci_config_tokens (void);
>> diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
>> index ab147a1909c8..341ed71250f1 100644
>> --- a/arch/powerpc/kernel/pci_dn.c
>> +++ b/arch/powerpc/kernel/pci_dn.c
>> @@ -40,7 +40,7 @@
>> * one of PF's bridge. For other devices, their firmware
>> * data is linked to that of their bridge.
>> */
>> -static struct pci_dn *pci_bus_to_pdn(struct pci_bus *bus)
>> +struct pci_dn *pci_bus_to_pdn(struct pci_bus *bus)
>> {
>> struct pci_bus *pbus;
>> struct device_node *dn;
>> diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
>> index 3260250d2029..73c2d0aed996 100644
>> --- a/arch/powerpc/platforms/powernv/pci.c
>> +++ b/arch/powerpc/platforms/powernv/pci.c
>> @@ -761,6 +761,21 @@ static inline pnv_pci_cfg_check(struct pci_dn *pdn)
>> }
>> #endif /* CONFIG_EEH */
>>
>> +static int get_bus_pe_number(struct pci_bus *bus)
>> +{
>> + struct pci_dn *pdn = pci_bus_to_pdn(bus);
>> + struct pci_dn *child;
>> +
>> + if (!pdn)
>> + return IODA_INVALID_PE;
>> +
>> + list_for_each_entry(child, &pdn->child_list, list)
>> + if (child->pe_number != IODA_INVALID_PE)
>> + return child->pe_number;
>> +
>> + return IODA_INVALID_PE;
>> +}
>> +
>> static int pnv_pci_read_config(struct pci_bus *bus,
>> unsigned int devfn,
>> int where, int size, u32 *val)
>> @@ -769,12 +784,23 @@ static int pnv_pci_read_config(struct pci_bus *bus,
>> struct pci_controller *hose = pci_bus_to_host(bus);
>> struct pnv_phb *phb = hose->private_data;
>> int ret;
>> + u32 empty_val = 0xFFFFFFFF;
>>
>> - *val = 0xFFFFFFFF;
>> + *val = empty_val;
>> pdn = pci_get_pdn_by_devfn(bus, devfn);
>> - if (!pdn)
>> - return pnv_pci_cfg_read_raw(phb->opal_id, bus->number, devfn,
>> - where, size, val);
>> + if (!pdn) {
>> + int pe_number = get_bus_pe_number(bus);
>> +
>> + ret = pnv_pci_cfg_read_raw(phb->opal_id, bus->number, devfn,
>> + where, size, val);
>> +
>> + if (!ret && (*val == empty_val) && phb->unfreeze_pe)
>
> Do this empty val check work when using 1 or 2 byte cfg accesses?
>
That was intentional because 0xff and 0xffff are valid values, but the
0xffffffff is the only reliable sign of an empty slot. And the kernel
pokes a slot by the pci_bus_generic_read_dev_vendor_id() function, which
in turn tries to pci_bus_read_config_dword(PCI_VENDOR_ID).
But I haven't tried actually to read 1-2 bytes from an empty slot to
test if that triggers an EEH. If it does, I'll change that to
EEH_IO_ERROR_VALUE(size).
>> + phb->unfreeze_pe(phb, (pe_number == IODA_INVALID_PE) ?
>> + 0xff : pe_number,
>
> Use phb->ioda.reserved_pe_idx rather than guessing that 0xff is safe
> to use. On P9 we have PHBs with 512 PEs and some older P8 firmware
> releases used 0 as the reserved PE rather than 0xff.
>
Thanks for the catch! I'll fix that in v5.
Best regards,
Serge
>> + OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
>> +
>> + return ret;
>> + }
>>
>> if (!pnv_pci_cfg_check(pdn))
>> return PCIBIOS_DEVICE_NOT_FOUND;
>> --
>> 2.20.1
>>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* REPOST [PATCH v04] powerpc/numa: Perform full re-add of CPU for PRRN/VPHN topology update
From: Michael Bringmann @ 2019-03-05 15:13 UTC (permalink / raw)
To: linuxppc-dev, linux-kernel
Cc: Rob Herring, Srikar Dronamraju, Kees Cook, Nicholas Piggin,
Al Viro, Michael Bringmann, Juliet Kim, Paul Mackerras,
Tyrel Datwyler, Nathan Lynch, Oliver O'Halloran,
Thomas Falcon, Guenter Roeck, Corentin Labbe
On pseries systems, performing changes to a partition's affinity
can result in altering the nodes a CPU is assigned to the
current system. For example, some systems are subject to resource
balancing operations by the operator or control software. In such
environments, system CPUs may be in node 1 and 3 at boot, and be
moved to nodes 2, 3, and 5, for better performance.
The current implementation attempts to recognize such changes within
the powerpc-specific version of arch_update_cpu_topology to modify a
range of system data structures directly. However, some scheduler
data structures may be inaccessible, or the timing of a node change
may still lead to corruption or error in other modules (e.g. user
space) which do not receive notification of these changes.
This patch modifies the PRRN/VPHN topology update worker function to
recognize an affinity change for a CPU, and to perform a full DLPAR
remove and add of the CPU instead of dynamically changing its node
to resolve this issue.
[Based upon patch submission:
Subject: [PATCH] powerpc/pseries: Perform full re-add of CPU for topology update post-migration
From: Nathan Fontenot <nfont@linux.vnet.ibm.com>
Date: Tue Oct 30 05:43:36 AEDT 2018
]
[Replace patch submission:
Subject: [PATCH] powerpc/topology: Update numa mask when cpu node mapping changes
From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Date: Wed Oct 10 15:24:46 AEDT 2018
]
Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
---
Changes in v04:
-- Revise tests in topology_timer_fn to check vphn_enabled before prrn_enabled
-- Remove unnecessary changes to numa_update_cpu_topology
Changes in v03:
-- Fixed under-scheduling of topo updates.
Changes in v02:
-- Reuse more of the previous implementation to reduce patch size
-- Replace former calls to numa_update_cpu_topology(false) by
topology_schedule_update
-- Make sure that we report topology changes back through
arch_update_cpu_topology
-- Fix problem observed in powerpc next kernel with updating
cpu_associativity_changes_mask in timer_topology_fn when both
prrn_enabled and vphn_enabled, and many extra CPUs are possible,
but not installed.
-- Fix problem with updating cpu_associativity_changes_mask when
VPHN associativity information does not arrive until after first
call to update topology occurs.
---
arch/powerpc/include/asm/topology.h | 7 +----
arch/powerpc/kernel/rtasd.c | 2 +
arch/powerpc/mm/numa.c | 47 +++++++++++++++++++++++------------
3 files changed, 34 insertions(+), 22 deletions(-)
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index f85e2b01c3df..79505c371fd5 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -42,7 +42,7 @@ extern void __init dump_numa_cpu_topology(void);
extern int sysfs_add_device_to_node(struct device *dev, int nid);
extern void sysfs_remove_device_from_node(struct device *dev, int nid);
-extern int numa_update_cpu_topology(bool cpus_locked);
+extern void topology_schedule_update(void);
static inline void update_numa_cpu_lookup_table(unsigned int cpu, int node)
{
@@ -77,10 +77,7 @@ static inline void sysfs_remove_device_from_node(struct device *dev,
{
}
-static inline int numa_update_cpu_topology(bool cpus_locked)
-{
- return 0;
-}
+static inline void topology_schedule_update(void) {}
static inline void update_numa_cpu_lookup_table(unsigned int cpu, int node) {}
diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c
index 8a1746d755c9..b1828de7ab78 100644
--- a/arch/powerpc/kernel/rtasd.c
+++ b/arch/powerpc/kernel/rtasd.c
@@ -285,7 +285,7 @@ static void handle_prrn_event(s32 scope)
* the RTAS event.
*/
pseries_devicetree_update(-scope);
- numa_update_cpu_topology(false);
+ topology_schedule_update();
}
static void handle_rtas_event(const struct rtas_error_log *log)
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index b5d1c45c1475..eb63479f09d7 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -1077,6 +1077,8 @@ static int prrn_enabled;
static void reset_topology_timer(void);
static int topology_timer_secs = 1;
static int topology_inited;
+static int topology_update_in_progress;
+static int topology_changed;
/*
* Change polling interval for associativity changes.
@@ -1297,9 +1299,9 @@ static int update_lookup_table(void *data)
* Update the node maps and sysfs entries for each cpu whose home node
* has changed. Returns 1 when the topology has changed, and 0 otherwise.
*
- * cpus_locked says whether we already hold cpu_hotplug_lock.
+ * readd_cpus: Also readd any CPUs that have changed affinity
*/
-int numa_update_cpu_topology(bool cpus_locked)
+static int numa_update_cpu_topology(bool readd_cpus)
{
unsigned int cpu, sibling, changed = 0;
struct topology_update_data *updates, *ud;
@@ -1307,7 +1309,8 @@ int numa_update_cpu_topology(bool cpus_locked)
struct device *dev;
int weight, new_nid, i = 0;
- if (!prrn_enabled && !vphn_enabled && topology_inited)
+ if ((!prrn_enabled && !vphn_enabled && topology_inited) ||
+ topology_update_in_progress)
return 0;
weight = cpumask_weight(&cpu_associativity_changes_mask);
@@ -1318,6 +1321,8 @@ int numa_update_cpu_topology(bool cpus_locked)
if (!updates)
return 0;
+ topology_update_in_progress = 1;
+
cpumask_clear(&updated_cpus);
for_each_cpu(cpu, &cpu_associativity_changes_mask) {
@@ -1339,16 +1344,21 @@ int numa_update_cpu_topology(bool cpus_locked)
new_nid = find_and_online_cpu_nid(cpu);
- if (new_nid == numa_cpu_lookup_table[cpu]) {
+ if ((new_nid == numa_cpu_lookup_table[cpu]) ||
+ !cpu_present(cpu)) {
cpumask_andnot(&cpu_associativity_changes_mask,
&cpu_associativity_changes_mask,
cpu_sibling_mask(cpu));
- dbg("Assoc chg gives same node %d for cpu%d\n",
+ if (cpu_present(cpu))
+ dbg("Assoc chg gives same node %d for cpu%d\n",
new_nid, cpu);
cpu = cpu_last_thread_sibling(cpu);
continue;
}
+ if (readd_cpus)
+ dlpar_cpu_readd(cpu);
+
for_each_cpu(sibling, cpu_sibling_mask(cpu)) {
ud = &updates[i++];
ud->next = &updates[i];
@@ -1390,7 +1400,7 @@ int numa_update_cpu_topology(bool cpus_locked)
if (!cpumask_weight(&updated_cpus))
goto out;
- if (cpus_locked)
+ if (!readd_cpus)
stop_machine_cpuslocked(update_cpu_topology, &updates[0],
&updated_cpus);
else
@@ -1401,9 +1411,9 @@ int numa_update_cpu_topology(bool cpus_locked)
* offline CPUs. It is best to perform this update from the stop-
* machine context.
*/
- if (cpus_locked)
+ if (!readd_cpus)
stop_machine_cpuslocked(update_lookup_table, &updates[0],
- cpumask_of(raw_smp_processor_id()));
+ cpumask_of(raw_smp_processor_id()));
else
stop_machine(update_lookup_table, &updates[0],
cpumask_of(raw_smp_processor_id()));
@@ -1420,35 +1430,40 @@ int numa_update_cpu_topology(bool cpus_locked)
}
out:
+ topology_update_in_progress = 0;
kfree(updates);
return changed;
}
int arch_update_cpu_topology(void)
{
- return numa_update_cpu_topology(true);
+ return numa_update_cpu_topology(false);
}
static void topology_work_fn(struct work_struct *work)
{
- rebuild_sched_domains();
+ lock_device_hotplug();
+ if (numa_update_cpu_topology(true))
+ rebuild_sched_domains();
+ unlock_device_hotplug();
}
static DECLARE_WORK(topology_work, topology_work_fn);
-static void topology_schedule_update(void)
+void topology_schedule_update(void)
{
- schedule_work(&topology_work);
+ if (!topology_update_in_progress)
+ schedule_work(&topology_work);
}
static void topology_timer_fn(struct timer_list *unused)
{
- if (prrn_enabled && cpumask_weight(&cpu_associativity_changes_mask))
- topology_schedule_update();
- else if (vphn_enabled) {
+ if (vphn_enabled) {
if (update_cpu_associativity_changes_mask() > 0)
topology_schedule_update();
reset_topology_timer();
}
+ else if (prrn_enabled && cpumask_weight(&cpu_associativity_changes_mask))
+ topology_schedule_update();
}
static struct timer_list topology_timer;
@@ -1553,7 +1568,7 @@ void __init shared_proc_topology_init(void)
if (lppaca_shared_proc(get_lppaca())) {
bitmap_fill(cpumask_bits(&cpu_associativity_changes_mask),
nr_cpumask_bits);
- numa_update_cpu_topology(false);
+ topology_schedule_update();
}
}
^ permalink raw reply related
* [PATCH v2] powerpc: Disable kcov for slb routines.
From: Mahesh J Salgaonkar @ 2019-03-05 12:06 UTC (permalink / raw)
To: linuxppc-dev; +Cc: syzkaller, Paul Mackerras, Nicholas Piggin, Andrew Donnellan
From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
The kcov instrumentation inside SLB routines causes duplicate SLB entries
to be added resulting into SLB multihit machine checks.
Disable kcov instrumentation on slb.o
Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Acked-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com>
---
Change in v2:
- Add comment as requested by Andrew
---
arch/powerpc/mm/Makefile | 3 +++
1 file changed, 3 insertions(+)
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
index d4d32e229ace..eb16449e694c 100644
--- a/arch/powerpc/mm/Makefile
+++ b/arch/powerpc/mm/Makefile
@@ -60,3 +60,6 @@ obj-$(CONFIG_PPC_MEM_KEYS) += pkeys.o
# This is necessary for booting with kcov enabled on book3e machines
KCOV_INSTRUMENT_tlb_nohash.o := n
KCOV_INSTRUMENT_fsl_booke_mmu.o := n
+
+# Disable kcov instrumentation on sensitive code for book3s_64 machines
+KCOV_INSTRUMENT_slb.o := n
^ permalink raw reply related
* Re: [RFC v3] sched/topology: fix kernel crash when a CPU is hotplugged in a memoryless node
From: Peter Zijlstra @ 2019-03-05 11:59 UTC (permalink / raw)
To: Laurent Vivier
Cc: Srikar Dronamraju, linux-kernel, Michael Bringmann, Ingo Molnar,
Suravee Suthikulpanit, Nathan Fontenot, Borislav Petkov,
linuxppc-dev, David Gibson
In-Reply-To: <20190304195952.16879-1-lvivier@redhat.com>
On Mon, Mar 04, 2019 at 08:59:52PM +0100, Laurent Vivier wrote:
> This happens because initially powerpc code computes
> sched_domains_numa_masks of offline nodes as if they were merged with
> node 0 (because firmware doesn't provide the distance information for
> memoryless/cpuless nodes):
>
> node 0 1 2 3
> 0: 10 40 10 10
> 1: 40 10 40 40
> 2: 10 40 10 10
> 3: 10 40 10 10
*groan*... what does it do for things like percpu memory? ISTR the
per-cpu chunks are all allocated early too. Having them all use memory
out of node-0 would seem sub-optimal.
> We should have:
>
> node 0 1 2 3
> 0: 10 40 40 40
> 1: 40 10 40 40
> 2: 40 40 10 40
> 3: 40 40 40 10
Can it happen that it introduces a new distance in the table? One that
hasn't been seen before? This example only has 10 and 40, but suppose
the new node lands at distance 20 (or 80); can such a thing happen?
If not; why not?
> diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c
> index 3f35ba1d8fde..24831b86533b 100644
> --- a/kernel/sched/topology.c
> +++ b/kernel/sched/topology.c
> @@ -1622,8 +1622,10 @@ void sched_init_numa(void)
> return;
>
> sched_domains_numa_masks[i][j] = mask;
> + if (!node_state(j, N_ONLINE))
> + continue;
>
> - for_each_node(k) {
> + for_each_online_node(k) {
> if (node_distance(j, k) > sched_domains_numa_distance[i])
> continue;
>
So you're relying on sched_domain_numa_masks_set/clear() to fix this up,
but that in turn relies on the sched_domain_numa_levels thing to stay
accurate.
This all seems very fragile and unfortunate.
^ permalink raw reply
* Re: [PATCH RFC v4 3/9] powerpc/pci: Create pci_dn on demand
From: Oliver @ 2019-03-05 8:04 UTC (permalink / raw)
To: Sergey Miroshnichenko
Cc: Stewart Smith, Alexey Kardashevskiy, linux, linuxppc-dev
In-Reply-To: <20190301160440.26262-4-s.miroshnichenko@yadro.com>
On Sat, Mar 2, 2019 at 3:04 AM Sergey Miroshnichenko
<s.miroshnichenko@yadro.com> wrote:
>
> If a struct pci_dn hasn't yet been created for the PCIe device (there was
> no DT node for it), allocate this structure and fill with info read from
> the device directly.
>
> Signed-off-by: Sergey Miroshnichenko <s.miroshnichenko@yadro.com>
> ---
> arch/powerpc/kernel/pci_dn.c | 79 ++++++++++++++++++++++++++++++++----
> 1 file changed, 72 insertions(+), 7 deletions(-)
>
> diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
> index 341ed71250f1..67ccd7be8344 100644
> --- a/arch/powerpc/kernel/pci_dn.c
> +++ b/arch/powerpc/kernel/pci_dn.c
> @@ -33,6 +33,8 @@
> #include <asm/firmware.h>
> #include <asm/eeh.h>
>
> +static struct pci_dn *create_pdn(struct pci_dev *pdev, struct pci_dn *parent);
> +
> /*
> * The function is used to find the firmware data of one
> * specific PCI device, which is attached to the indicated
> @@ -65,6 +67,9 @@ struct pci_dn *pci_bus_to_pdn(struct pci_bus *bus)
> dn = pci_bus_to_OF_node(pbus);
> pdn = dn ? PCI_DN(dn) : NULL;
>
> + if (!pdn && pbus->self)
> + pdn = pbus->self->dev.archdata.pci_data;
> +
> return pdn;
> }
>
> @@ -74,10 +79,13 @@ struct pci_dn *pci_get_pdn_by_devfn(struct pci_bus *bus,
> struct device_node *dn = NULL;
> struct pci_dn *parent, *pdn;
> struct pci_dev *pdev = NULL;
> + bool pdev_found = false;
>
> /* Fast path: fetch from PCI device */
> list_for_each_entry(pdev, &bus->devices, bus_list) {
> if (pdev->devfn == devfn) {
> + pdev_found = true;
> +
> if (pdev->dev.archdata.pci_data)
> return pdev->dev.archdata.pci_data;
>
> @@ -86,6 +94,9 @@ struct pci_dn *pci_get_pdn_by_devfn(struct pci_bus *bus,
> }
> }
>
> + if (!pdev_found)
> + pdev = NULL;
> +
> /* Fast path: fetch from device node */
> pdn = dn ? PCI_DN(dn) : NULL;
> if (pdn)
> @@ -98,9 +109,12 @@ struct pci_dn *pci_get_pdn_by_devfn(struct pci_bus *bus,
>
> list_for_each_entry(pdn, &parent->child_list, list) {
> if (pdn->busno == bus->number &&
> - pdn->devfn == devfn)
> - return pdn;
> - }
> + pdn->devfn == devfn) {
> + if (pdev)
> + pdev->dev.archdata.pci_data = pdn;
> + return pdn;
> + }
> + }
>
> return NULL;
> }
> @@ -130,14 +144,15 @@ struct pci_dn *pci_get_pdn(struct pci_dev *pdev)
>
> list_for_each_entry(pdn, &parent->child_list, list) {
> if (pdn->busno == pdev->bus->number &&
> - pdn->devfn == pdev->devfn)
> + pdn->devfn == pdev->devfn) {
> + pdev->dev.archdata.pci_data = pdn;
> return pdn;
> + }
> }
>
> - return NULL;
> + return create_pdn(pdev, parent);
> }
Eh... If it works I guess it's fine? Killing pdn entirely (or at the
very least greatly restricting it's role) is something we should work
towards though since it doesn't make much sense on PNV.
> -#ifdef CONFIG_PCI_IOV
> static struct pci_dn *add_one_dev_pci_data(struct pci_dn *parent,
> int vf_index,
> int busno, int devfn)
> @@ -156,7 +171,9 @@ static struct pci_dn *add_one_dev_pci_data(struct pci_dn *parent,
> pdn->parent = parent;
> pdn->busno = busno;
> pdn->devfn = devfn;
> + #ifdef CONFIG_PCI_IOV
> pdn->vf_index = vf_index;
> + #endif /* CONFIG_PCI_IOV */
This function is currently only used when adding VFs, so I'd move the
VF specific params from this and put them in the call site at
add_dev_pci_data(). Then you can drop the #ifdef hacks. It might be
worth renaming add_one_dev_pci_data() and add_one_dev_pci_data() since
their actual usage is limited to the VF init path, but their name seem
generic.
> pdn->pe_number = IODA_INVALID_PE;
> INIT_LIST_HEAD(&pdn->child_list);
> INIT_LIST_HEAD(&pdn->list);
> @@ -164,7 +181,55 @@ static struct pci_dn *add_one_dev_pci_data(struct pci_dn *parent,
>
> return pdn;
> }
> -#endif
> +
> +static struct pci_dn *create_pdn(struct pci_dev *pdev, struct pci_dn *parent)
> +{
> + struct pci_dn *pdn = NULL;
> +
> + if (!parent)
> + return NULL;
> +
> + pdn = add_one_dev_pci_data(parent, 0, pdev->bus->busn_res.start, pdev->devfn);
> + dev_info(&pdev->dev, "Create a new pdn for devfn %2x\n", pdev->devfn / 8);
> +
> + if (pdn) {
Check for !pdn and exit early. Stacking indentation levels just gets
kind of ugly.
> + #ifdef CONFIG_EEH
> + struct eeh_dev *edev;
> + #endif /* CONFIG_EEH */
You don't use the variable for anything. You can either switch this to
a void pointer or just check the return value of eeh_dev_init()
directly and drop this.
> + u32 class_code;
> + u16 device_id;
> + u16 vendor_id;
> +
> + #ifdef CONFIG_EEH
> + edev = eeh_dev_init(pdn);
> + if (!edev) {
> + kfree(pdn);
> + dev_err(&pdev->dev, "%s: Failed to allocate edev\n", __func__);
> + return NULL;
> + }
> + #endif /* CONFIG_EEH */
> +
> + pci_bus_read_config_word(pdev->bus, pdev->devfn,
> + PCI_VENDOR_ID, &vendor_id);
> + pdn->vendor_id = vendor_id;
> +
> + pci_bus_read_config_word(pdev->bus, pdev->devfn,
> + PCI_DEVICE_ID, &device_id);
> + pdn->device_id = device_id;
> +
> + pci_bus_read_config_dword(pdev->bus, pdev->devfn,
> + PCI_CLASS_REVISION, &class_code);
> + class_code >>= 8;
> + pdn->class_code = class_code;
> +
> + pdn->pci_ext_config_space = 0;
Does this need to be explicitly initialised or can we rely on it being
allocated with kzalloc() or similar?
> + pdev->dev.archdata.pci_data = pdn;
> + } else {
> + dev_err(&pdev->dev, "%s: Failed to allocate pdn\n", __func__);
> + }
> +
> + return pdn;
> +}
>
> struct pci_dn *add_dev_pci_data(struct pci_dev *pdev)
> {
> --
> 2.20.1
>
^ permalink raw reply
* Printing of machine check severity
From: Michael Ellerman @ 2019-03-05 6:57 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Mahesh J Salgaonkar, satheera, Nicholas Piggin
Hi all,
RE: https://github.com/linuxppc/issues/issues/230
> Host dmesg throws lot of below SLB [Multihit] HMI's
>
> [295216.837358] Severe Machine check interrupt [Recovered]
> [295216.837365] Harmless Hypervisor Maintenance interrupt [Recovered]
> [295216.837374] Guest NIP: c00000000024a7dc
> [295216.837378] Error detail: Processor Recovery done
> [295216.837381] HMER: 2040000000000000
> [295216.837388] Initiator: CPU
> [295216.837406] Error type: SLB [Multihit]
> [295216.837415] Effective address: d00000000316c400
Paul points out that these aren't severe errors from the hosts point of
view, and possibly not even for the guest.
I think the key problem here is that we print "Severe" for most types of
MCEs, even though some really aren't.
That comes from the severity being set to `MCE_SEV_ERROR_SYNC` in the
i/derror table.
All the enum values are `MCE_SEV` so the value is actually `ERROR_SYNC`,
which I think means "synchronous error". That is correct. But I don't
think it's correct that all synchronous errors are "severe".
We also have some errors in `mce_ierror_table` that are marked
`MCE_SEV_FATAL` and then have a comment saying `/* ASYNC is fatal */`.
So I feel like we have severity and sync/async conflated in the severity
value, ie. we should split out sync/async and then have a separate
severity field.
We need to be careful because a few places check for `MCE_SEV_ERROR_SYNC`,
it's not *only* used for the severity string.
We could then mark eg. SLB multi-hits as warning rather than severe.
Additionally we probably want to use the `in_guest` flag to modulate the
severity or the message, or both.
cheers
^ permalink raw reply
* Re: [PATCH RFC v4 2/9] powerpc/powernv/pci: Suppress an EEH error when reading an empty slot
From: Oliver @ 2019-03-05 6:14 UTC (permalink / raw)
To: Sergey Miroshnichenko
Cc: Stewart Smith, Alexey Kardashevskiy, linux, linuxppc-dev
In-Reply-To: <20190301160440.26262-3-s.miroshnichenko@yadro.com>
On Sat, Mar 2, 2019 at 3:04 AM Sergey Miroshnichenko
<s.miroshnichenko@yadro.com> wrote:
>
> Reading an empty slot returns all ones, which triggers a false
> EEH error event on PowerNV. This patch unfreezes the bus where
> it has happened.
>
> Signed-off-by: Sergey Miroshnichenko <s.miroshnichenko@yadro.com>
> ---
> arch/powerpc/include/asm/ppc-pci.h | 1 +
> arch/powerpc/kernel/pci_dn.c | 2 +-
> arch/powerpc/platforms/powernv/pci.c | 34 ++++++++++++++++++++++++----
> 3 files changed, 32 insertions(+), 5 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h
> index f67da277d652..737393c54f58 100644
> --- a/arch/powerpc/include/asm/ppc-pci.h
> +++ b/arch/powerpc/include/asm/ppc-pci.h
> @@ -40,6 +40,7 @@ void *traverse_pci_dn(struct pci_dn *root,
> void *(*fn)(struct pci_dn *, void *),
> void *data);
> extern void pci_devs_phb_init_dynamic(struct pci_controller *phb);
> +struct pci_dn *pci_bus_to_pdn(struct pci_bus *bus);
>
> /* From rtas_pci.h */
> extern void init_pci_config_tokens (void);
> diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c
> index ab147a1909c8..341ed71250f1 100644
> --- a/arch/powerpc/kernel/pci_dn.c
> +++ b/arch/powerpc/kernel/pci_dn.c
> @@ -40,7 +40,7 @@
> * one of PF's bridge. For other devices, their firmware
> * data is linked to that of their bridge.
> */
> -static struct pci_dn *pci_bus_to_pdn(struct pci_bus *bus)
> +struct pci_dn *pci_bus_to_pdn(struct pci_bus *bus)
> {
> struct pci_bus *pbus;
> struct device_node *dn;
> diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
> index 3260250d2029..73c2d0aed996 100644
> --- a/arch/powerpc/platforms/powernv/pci.c
> +++ b/arch/powerpc/platforms/powernv/pci.c
> @@ -761,6 +761,21 @@ static inline pnv_pci_cfg_check(struct pci_dn *pdn)
> }
> #endif /* CONFIG_EEH */
>
> +static int get_bus_pe_number(struct pci_bus *bus)
> +{
> + struct pci_dn *pdn = pci_bus_to_pdn(bus);
> + struct pci_dn *child;
> +
> + if (!pdn)
> + return IODA_INVALID_PE;
> +
> + list_for_each_entry(child, &pdn->child_list, list)
> + if (child->pe_number != IODA_INVALID_PE)
> + return child->pe_number;
> +
> + return IODA_INVALID_PE;
> +}
> +
> static int pnv_pci_read_config(struct pci_bus *bus,
> unsigned int devfn,
> int where, int size, u32 *val)
> @@ -769,12 +784,23 @@ static int pnv_pci_read_config(struct pci_bus *bus,
> struct pci_controller *hose = pci_bus_to_host(bus);
> struct pnv_phb *phb = hose->private_data;
> int ret;
> + u32 empty_val = 0xFFFFFFFF;
>
> - *val = 0xFFFFFFFF;
> + *val = empty_val;
> pdn = pci_get_pdn_by_devfn(bus, devfn);
> - if (!pdn)
> - return pnv_pci_cfg_read_raw(phb->opal_id, bus->number, devfn,
> - where, size, val);
> + if (!pdn) {
> + int pe_number = get_bus_pe_number(bus);
> +
> + ret = pnv_pci_cfg_read_raw(phb->opal_id, bus->number, devfn,
> + where, size, val);
> +
> + if (!ret && (*val == empty_val) && phb->unfreeze_pe)
Do this empty val check work when using 1 or 2 byte cfg accesses?
> + phb->unfreeze_pe(phb, (pe_number == IODA_INVALID_PE) ?
> + 0xff : pe_number,
Use phb->ioda.reserved_pe_idx rather than guessing that 0xff is safe
to use. On P9 we have PHBs with 512 PEs and some older P8 firmware
releases used 0 as the reserved PE rather than 0xff.
> + OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
> +
> + return ret;
> + }
>
> if (!pnv_pci_cfg_check(pdn))
> return PCIBIOS_DEVICE_NOT_FOUND;
> --
> 2.20.1
>
^ permalink raw reply
* [PATCH] powerpc: config: Sync skiroot defconfig
From: Joel Stanley @ 2019-03-05 4:46 UTC (permalink / raw)
To: linuxppc-dev
This updates the skiroot defconfig with the version from the OpenPower
firmwre build tree.
Important changes are the addition of QED and E1000E ethernet drivers.
Signed-off-by: Joel Stanley <joel@jms.id.au>
---
Generated on top of next-20190304
arch/powerpc/configs/skiroot_defconfig | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/configs/skiroot_defconfig b/arch/powerpc/configs/skiroot_defconfig
index bf31334efbce..b3a9ea838244 100644
--- a/arch/powerpc/configs/skiroot_defconfig
+++ b/arch/powerpc/configs/skiroot_defconfig
@@ -52,10 +52,10 @@ CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_FORCE=y
CONFIG_MODULE_SIG_SHA512=y
CONFIG_PARTITION_ADVANCED=y
-# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_MQ_IOSCHED_DEADLINE is not set
+# CONFIG_MQ_IOSCHED_KYBER is not set
# CONFIG_COMPACTION is not set
# CONFIG_MIGRATION is not set
-# CONFIG_BOUNCE is not set
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -136,9 +136,11 @@ CONFIG_ACENIC_OMIT_TIGON_I=y
# CONFIG_NET_VENDOR_AQUANTIA is not set
# CONFIG_NET_VENDOR_ARC is not set
# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_VENDOR_AURORA is not set
CONFIG_TIGON3=m
CONFIG_BNX2X=m
# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_CADENCE is not set
# CONFIG_NET_VENDOR_CAVIUM is not set
CONFIG_CHELSIO_T1=m
# CONFIG_NET_VENDOR_CISCO is not set
@@ -150,6 +152,7 @@ CONFIG_BE2NET=m
# CONFIG_NET_VENDOR_HP is not set
# CONFIG_NET_VENDOR_HUAWEI is not set
CONFIG_E1000=m
+CONFIG_E1000E=m
CONFIG_IGB=m
CONFIG_IXGB=m
CONFIG_IXGBE=m
@@ -159,6 +162,7 @@ CONFIG_MLX4_EN=m
# CONFIG_MLX4_CORE_GEN2 is not set
CONFIG_MLX5_CORE=m
# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MICROSEMI is not set
CONFIG_MYRI10GE=m
# CONFIG_NET_VENDOR_NATSEMI is not set
CONFIG_S2IO=m
@@ -166,8 +170,11 @@ CONFIG_S2IO=m
# CONFIG_NET_VENDOR_NI is not set
# CONFIG_NET_VENDOR_NVIDIA is not set
# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_VENDOR_PACKET_ENGINES is not set
CONFIG_QLGE=m
CONFIG_NETXEN_NIC=m
+CONFIG_QED=m
+CONFIG_QEDE=m
# CONFIG_NET_VENDOR_QUALCOMM is not set
# CONFIG_NET_VENDOR_RDC is not set
# CONFIG_NET_VENDOR_REALTEK is not set
--
2.20.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox