Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 01/11] arm64: use RET instruction for exiting the trampoline
From: Will Deacon @ 2018-01-08 14:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAKv+Gu_F_hWvF7CghnDCQGCaxeViTZjvT=zqdFdD5rqdORCceQ@mail.gmail.com>

On Mon, Jan 08, 2018 at 02:38:00PM +0000, Ard Biesheuvel wrote:
> On 8 January 2018 at 14:33, Will Deacon <will.deacon@arm.com> wrote:
> > On Sat, Jan 06, 2018 at 01:13:23PM +0000, Ard Biesheuvel wrote:
> >> On 5 January 2018 at 13:12, Will Deacon <will.deacon@arm.com> wrote:
> >> > Speculation attacks against the entry trampoline can potentially resteer
> >> > the speculative instruction stream through the indirect branch and into
> >> > arbitrary gadgets within the kernel.
> >> >
> >> > This patch defends against these attacks by forcing a misprediction
> >> > through the return stack: a dummy BL instruction loads an entry into
> >> > the stack, so that the predicted program flow of the subsequent RET
> >> > instruction is to a branch-to-self instruction which is finally resolved
> >> > as a branch to the kernel vectors with speculation suppressed.
> >> >
> >>
> >> How safe is it to assume that every microarchitecture will behave as
> >> expected here? Wouldn't it be safer in general not to rely on a memory
> >> load for x30 in the first place? (see below) Or may the speculative
> >> execution still branch anywhere even if the branch target is
> >> guaranteed to be known by that time?
> >
> > The main problem with this approach is that EL0 can read out the text and
> > find the kaslr offset.
> 
> Not really - the CONFIG_RANDOMIZE_BASE path puts the movz/movk
> sequence in the next page, but that does involve an unconditional
> branch.

Ah sorry, I had missed that. The unconditional branch may still be attacked,
however.

> > The memory load is fine, because the data page is
> > unmapped along with the kernel text. I'm not aware of any
> > micro-architectures where this patch doesn't do what we need.
> >
> 
> Well, the memory load is what may incur the delay, creating the window
> for speculative execution of the indirect branch. What I don't have
> enough of a handle on is whether this speculative execution may still
> branch to wherever the branch predictor is pointing even if the
> register containing the branch target is already available.

For the micro-architectures I'm aware of, the return stack predictor will
always safely mispredict the jump into the kernel vectors with this patch
applied.

Will

^ permalink raw reply

* [net-next: PATCH 0/8] Armada 7k/8k PP2 ACPI support
From: Graeme Gregory @ 2018-01-08 14:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180104162036.GL3401@lunn.ch>

On Thu, Jan 04, 2018 at 05:20:36PM +0100, Andrew Lunn wrote:
> > > I already agreed with 'reg' being awkward in the later emails.
> > > Wouldn't _ADR be more appropriate to specify PHY address on MDIO bus?
> > > 
> > Ah it is an actual address, then yes _ADR is probably more appropriate.
> 
> Newbie ACPI question. What is the definition of an address?
> 
> In this cause, we are talking about an address of a device on an MDIO
> bus. It takes a value between 0 and 31.
> 
> How are IC2 device addresses represented in ACPI? MDIO devices and I2C
> devices are pretty similar. So it would make sense to use the same as
> what I2C uses.
> 
Too big (and has table) to sensibly quote, but defined in ACPI spec

6.1.1 _ADR (Address)

Ive never though been quite sure if that is just an example list of
address types or its supposed to be canonical (in which case some ECRs
are needed to the spec).

Thanks

Graeme

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180108/3ef4716e/attachment.sig>

^ permalink raw reply

* [PATCH 1/3] arm: Add BTB invalidation on switch_mm for Cortex-A9, A12, A15 and A17
From: Marc Zyngier @ 2018-01-08 14:46 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <432481b8-11f0-6ee2-8b5c-5ac20f5f27db@arm.com>

On 08/01/18 14:29, Andre Przywara wrote:
> Hi,
> 
> On 06/01/18 12:09, Marc Zyngier wrote:
>> In order to avoid aliasing attacks against the branch predictor,
>> some implementations require to invalidate the BTB when switching
>> from one user context to another.
>>
>> For this, we reuse the existing implementation for Cortex-A8, and
>> apply it to A9, A12, A15, and A17.
>>
>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>> ---
>>  arch/arm/mm/proc-v7-2level.S |  4 ++--
>>  arch/arm/mm/proc-v7-3level.S |  6 ++++++
>>  arch/arm/mm/proc-v7.S        | 32 ++++++++++++++++----------------
>>  3 files changed, 24 insertions(+), 18 deletions(-)
>>
>> diff --git a/arch/arm/mm/proc-v7-2level.S b/arch/arm/mm/proc-v7-2level.S
>> index c6141a5435c3..0422e58b74e8 100644
>> --- a/arch/arm/mm/proc-v7-2level.S
>> +++ b/arch/arm/mm/proc-v7-2level.S
>> @@ -41,7 +41,7 @@
>>   *	even on Cortex-A8 revisions not affected by 430973.
>>   *	If IBE is not set, the flush BTAC/BTB won't do anything.
>>   */
>> -ENTRY(cpu_ca8_switch_mm)
>> +ENTRY(cpu_v7_btbinv_switch_mm)
>>  #ifdef CONFIG_MMU
>>  	mov	r2, #0
>>  	mcr	p15, 0, r2, c7, c5, 6		@ flush BTAC/BTB
>> @@ -66,7 +66,7 @@ ENTRY(cpu_v7_switch_mm)
>>  #endif
>>  	bx	lr
>>  ENDPROC(cpu_v7_switch_mm)
>> -ENDPROC(cpu_ca8_switch_mm)
>> +ENDPROC(cpu_v7_btbinv_switch_mm)
>>  
>>  /*
>>   *	cpu_v7_set_pte_ext(ptep, pte)
>> diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
>> index 7d16bbc4102b..934272e1fa08 100644
>> --- a/arch/arm/mm/proc-v7-3level.S
>> +++ b/arch/arm/mm/proc-v7-3level.S
>> @@ -54,6 +54,11 @@
>>   * Set the translation table base pointer to be pgd_phys (physical address of
>>   * the new TTB).
>>   */
>> +ENTRY(cpu_v7_btbinv_switch_mm)
>> +#ifdef CONFIG_MMU
>> +	mov	r2, #0
>> +	mcr	p15, 0, r2, c7, c5, 6			@ flush BTAC/BTB
> 
> r2 is already used below: this is the second argument to the function.
> The first argument is a phys_addr_t, so it takes both r0 and r1 already.
> That's why we need to use r3 above.
> This fixes a crash on the Midway for me.

I suppose you have DRAM above 4GB. Lucky you! I'll fix that in v2.

Thanks for the heads up.

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply

* [PATCH v6 08/10] pwm: pwm-omap-dmtimer: Adapt driver to utilize dmtimer pdata ops
From: Claudiu Beznea @ 2018-01-08 14:47 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <3b52c42c-8283-c7b9-6f82-1187766faab1@baylibre.com>



On 08.01.2018 16:44, Neil Armstrong wrote:
> On 08/01/2018 15:33, Keerthy wrote:
>>
>>
>> On Monday 08 January 2018 02:14 PM, Claudiu Beznea wrote:
>>>
>>>
>>> On 02.01.2018 12:09, Keerthy wrote:
>>>> Adapt driver to utilize dmtimer pdata ops instead of pdata-quirks.
>>>>
>>>> Signed-off-by: Keerthy <j-keerthy@ti.com>
>>>> Tested-by: Ladislav Michl <ladis@linux-mips.org>
>>>> ---
>>>>  drivers/pwm/pwm-omap-dmtimer.c | 39 ++++++++++++++++++++++-----------------
>>>>  1 file changed, 22 insertions(+), 17 deletions(-)
>>>>
>>>> diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c
>>>> index 5ad42f3..3b27aff 100644
>>>> --- a/drivers/pwm/pwm-omap-dmtimer.c
>>>> +++ b/drivers/pwm/pwm-omap-dmtimer.c
>>>> @@ -23,6 +23,7 @@
>>>>  #include <linux/mutex.h>
>>>>  #include <linux/of.h>
>>>>  #include <linux/of_platform.h>
>>>> +#include <linux/platform_data/dmtimer-omap.h>
>>>>  #include <linux/platform_data/pwm_omap_dmtimer.h>
>>>>  #include <linux/platform_device.h>
>>>>  #include <linux/pm_runtime.h>
>>>> @@ -37,7 +38,7 @@ struct pwm_omap_dmtimer_chip {
>>>>  	struct pwm_chip chip;
>>>>  	struct mutex mutex;
>>>>  	pwm_omap_dmtimer *dm_timer;
>>>> -	struct pwm_omap_dmtimer_pdata *pdata;
>>>> +	struct omap_dm_timer_ops *pdata;
>>>>  	struct platform_device *dm_timer_pdev;
>>>>  };
>>>>  
>>>> @@ -242,19 +243,33 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
>>>>  {
>>>>  	struct device_node *np = pdev->dev.of_node;
>>>>  	struct device_node *timer;
>>>> +	struct platform_device *timer_pdev;
>>>>  	struct pwm_omap_dmtimer_chip *omap;
>>>> -	struct pwm_omap_dmtimer_pdata *pdata;
>>>> +	struct dmtimer_platform_data *timer_pdata;
>>>> +	struct omap_dm_timer_ops *pdata;
>>>>  	pwm_omap_dmtimer *dm_timer;
>>>>  	u32 v;
>>>>  	int status;
>>>>  
>>>> -	pdata = dev_get_platdata(&pdev->dev);
>>>> -	if (!pdata) {
>>>> -		dev_err(&pdev->dev, "Missing dmtimer platform data\n");
>>>> +	timer = of_parse_phandle(np, "ti,timers", 0);
>>> of_node_put() should be called when done with device_node pointer returned
>>> by of_parse_phandle() (you may want to check the return ERROR cases below
>>> regarding this statement):
>>>> +	if (!timer)
>>>> +		return -ENODEV;
>>>> +
>>>> +	timer_pdev = of_find_device_by_node(timer);
>>>> +	if (!timer_pdev) {
>>>> +		dev_err(&pdev->dev, "Unable to find Timer pdev\n");
>>> here
>>>> +		return -ENODEV;
>>>> +	}
>>>> +
>>>> +	timer_pdata = dev_get_platdata(&timer_pdev->dev);
>>>> +	if (!timer_pdata) {
>>>> +		dev_err(&pdev->dev, "dmtimer pdata structure NULL\n");
>>> here
>>>>  		return -EINVAL;
>>>>  	}
>>>>  
>>>> -	if (!pdata->request_by_node ||
>>>> +	pdata = timer_pdata->timer_ops;
>>>> +
>>>> +	if (!pdata || !pdata->request_by_node ||
>>>>  	    !pdata->free ||
>>>>  	    !pdata->enable ||
>>>>  	    !pdata->disable ||
>>>> @@ -270,10 +285,6 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
>>>>  		return -EINVAL;
>>>>  	}
>>>>  
>>>> -	timer = of_parse_phandle(np, "ti,timers", 0);
>>>> -	if (!timer)
>>>> -		return -ENODEV;
>>>> -
>>>>  	if (!of_get_property(timer, "ti,timer-pwm", NULL)) {
>>> here
>>>>  		dev_err(&pdev->dev, "Missing ti,timer-pwm capability\n");
>>>>  		return -ENODEV;
>>>> @@ -291,13 +302,7 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev)
>>>>  
>>>>  	omap->pdata = pdata;
>>>>  	omap->dm_timer = dm_timer;
>>>> -
>>>> -	omap->dm_timer_pdev = of_find_device_by_node(timer);
>>>> -	if (!omap->dm_timer_pdev) {
>>>> -		dev_err(&pdev->dev, "Unable to find timer pdev\n");
>>>> -		omap->pdata->free(dm_timer);
>>>> -		return -EINVAL;
>>>> -	}
>>>> +	omap->dm_timer_pdev = timer_pdev;
>>>>  
>>>>  	/*
>>>>  	 * Ensure that the timer is stopped before we allow PWM core to call
>>>>
>>> And all the other return instructions from probe function not listed by git diff
>>
>> Thanks for reviewing. I will add the of_node_put call for all the error
>> paths.
After that you can add: Reviwed-by: Claudiu Beznea <claudiu.beznea@microchip.com>
>>
>>>
>>
>> _______________________________________________
>> linux-arm-kernel mailing list
>> linux-arm-kernel at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>>
> 
> Apart the missing of_node_put() :
> 
> Acked-by: Neil Armstrong <narmstrong@baylibre.com>
> 

^ permalink raw reply

* [PATCH v5 00/30] ARM Scalable Vector Extension (SVE)
From: Yury Norov @ 2018-01-08 14:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1509465082-30427-1-git-send-email-Dave.Martin@arm.com>

On Tue, Oct 31, 2017 at 03:50:52PM +0000, Dave Martin wrote:
> This series implements Linux kernel support for the ARM Scalable Vector
> Extension (SVE). [1]  It supersedes the previous v3: see [3] for link
> and full cover letter.
> 
> This is a minor update to v4, but does contain a couple of important
> fixes.
> 
> As in previous postings, the last two patches (here 29-30) are still
> RFC and not proposed for merging at this time.
> 
> The patches apply on
> git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git
> for-next/core
> d7b1d22d3821 ("arm64: uapi: Remove PSR_Q_BIT")
> 
> To reduce spam, some people may not been copied on the entire series.
> For those who did not receive the whole series, it can be found in the
> linux-arm-kernel archive. [2]
> 
> See the individual patches for details of changes.
> 
> For reviewer convenience, a git tree is available. [4]
> 
> Since there are some changes against already-reviewed patches, I've also
> pushed an unsquashed fixes tree for people to take a look at if it
> helps. [5]
> 
> 
> Summary:
> 
>  * "regset: Add support for dynamically sized regsets" fixed to avoid
>    x86 breakage;
> 
>  * one trival arm64 patch added to add asmlinkage annotations, and a
>    corresponding minor change to the Core task context handling patch;
> 
>  * one new arm64 fix ("signal: Verify extra data is user-readable in
>    sys_rt_sigreturn") to ensure that access_ok() checks are done for the
>    whole extended signal frame, not just the base frame;
> 
>  * one minor fix to the SVE sigreturn code to return consistent
>    intermediate error values (semantic correctness, non-functional
>    change);
> 
>  * one minor change to call __copy_from_user() instead of
>    copy_from_user() in a situation where there is already an access_ok()
>    check;
> 
> 
> [1] ARM Scalable Vector Extension
> https://community.arm.com/groups/processors/blog/2016/08/22/technology-update-the-scalable-vector-extension-sve-for-the-armv8-a-architecture
> 
> [2] linux-arm-kernel October 2017 Archives by thread
> http://lists.infradead.org/pipermail/linux-arm-kernel/2017-October/thread.html
> 
> [3] [PATCH v4 00/28] ARM Scalable Vector Extension (SVE)
> http://lists.infradead.org/pipermail/linux-arm-kernel/2017-October/539414.html
> 
> [4] For review and testing only -- **do not pull**
>     (This branch has review changelogs which should not form part of
>     the final commits.)
> 
>     v5 series (this posting)
> 
>     http://linux-arm.org/git?p=linux-dm.git;a=shortlog;h=refs/heads/sve/v5
>     git://linux-arm.org/linux-dm.git sve/v5
> 
> [5] For review and testing only -- **do not pull**
>     (This branch has review changelogs which should not form part of
>     the final commits.)
> 
>     v4 with unsquashed fixes
> 
>     http://linux-arm.org/git?p=linux-dm.git;a=shortlog;h=refs/heads/sve/v4%2Bfixes
>     git://linux-arm.org/linux-dm.git sve/v4+fixes

Hi Dave,

During rebase of my ILP32 series on 4.15 kernel I found that 
ILP32 needs to be enabled with SVE support, like you do for 
LP64 in this series.

I did all rebase work on this draft branch:
https://github.com/norov/linux/tree/ilp32-4.15-rc7

But any ILP32 program I tried crash, and the message in dmesg looks
like this:
[   39.510667] CPU: 0 PID: 1857 Comm: mytime Not tainted 4.15.0-rc7-00028-g45e0659df4d9 #41
[   39.510712] Hardware name: linux,dummy-virt (DT)
[   39.510829] pstate: 00000000 (nzcv daif -PAN -UAO)
[   39.511101] pc : 0x33488e28
[   39.511125] lr : 0x33488e28
[   39.511138] sp : 00000000fffef670
[   39.511158] x29: 000000005a536c33 x28: 0000000000000000 
[   39.511211] x27: 0000000000000000 x26: 0000000000000000 
[   39.511235] x25: 0000000000000000 x24: 0000000000000000 
[   39.511257] x23: 0000000000466000 x22: 0000000000000000 
[   39.511278] x21: 0000000000000000 x20: 000000000047f2a8 
[   39.511300] x19: 0000000000000000 x18: 0000000000000001 
[   39.511321] x17: 0000000000001000 x16: 0000000000001030 
[   39.511342] x15: 0000000000554e47 x14: 0000000000000001 
[   39.511364] x13: 0000000000000004 x12: 000000000000003c 
[   39.511385] x11: 0000100000000000 x10: 0800000000000000 
[   39.511406] x9 : 0fffffffffffffff x8 : 000000000000007c 
[   39.511427] x7 : 0000000000000077 x6 : 0000000000000041 
[   39.511448] x5 : 0000000000000411 x4 : 00000000fbad2488 
[   39.511468] x3 : 0000000000000001 x2 : 0000000000497950 
[   39.511489] x1 : 0000000000497550 x0 : 0000000000000001

(PC, LR and other registers may differ depending on test)

I'm pretty sure that this is SVE-related issue because if I disable
ARM64_SVE in config, everything becomes working.

I didn't get deep enough into this yet, and most probably there's
some stupid reason for crashing apps on my side, but in mail list
I found some sve-related patches that I cannot apply both on 4.15-rc
and next-20180108. And according to patch names, it is important
fixes, like this one:
https://www.spinics.net/lists/arm-kernel/msg619548.html

ILP32 code may spit some kernel issues from time to time, so there's
minor chance that the problem is not in ILP32 itself - that's why I
write this email to you.

What I want to ask you, do you have some branch with the most recent
SVE code that includes all fixes? Better if it would be 4.15-based
series, because we don't support ILP32 on next-* kernels now.

Also, if you have few minutes to take look at my series, I would
kindly ask you do this, because I still think that this is my
misunderstanding of how SVE should work for ILP32, and you as author
may just catch the bug at a glance.

Thanks,
Yury

^ permalink raw reply

* [net-next: PATCH 0/8] Armada 7k/8k PP2 ACPI support
From: Andrew Lunn @ 2018-01-08 14:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108144548.GA31502@xora-haswell>

On Mon, Jan 08, 2018 at 02:45:48PM +0000, Graeme Gregory wrote:
> On Thu, Jan 04, 2018 at 05:20:36PM +0100, Andrew Lunn wrote:
> > > > I already agreed with 'reg' being awkward in the later emails.
> > > > Wouldn't _ADR be more appropriate to specify PHY address on MDIO bus?
> > > > 
> > > Ah it is an actual address, then yes _ADR is probably more appropriate.
> > 
> > Newbie ACPI question. What is the definition of an address?
> > 
> > In this cause, we are talking about an address of a device on an MDIO
> > bus. It takes a value between 0 and 31.
> > 
> > How are IC2 device addresses represented in ACPI? MDIO devices and I2C
> > devices are pretty similar. So it would make sense to use the same as
> > what I2C uses.
> > 
> Too big (and has table) to sensibly quote, but defined in ACPI spec
> 
> 6.1.1 _ADR (Address)
> 
> Ive never though been quite sure if that is just an example list of
> address types or its supposed to be canonical (in which case some ECRs
> are needed to the spec).

Hi Graeme

I took a quick look at version 6.2, and noticed i2c devices use
_ADR(). So using it for MDIO seems O.K.

However, i2c, spi and uart devices all seem to be described using
GenericSerialBus. Maybe the correct way to describe MDIO devices is to
also use GenericSerialBus?

     Andrew

^ permalink raw reply

* [PATCH] perf: arm_dsu_pmu: convert to bitmap_from_arr32
From: Suzuki K Poulose @ 2018-01-08 14:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108124902.3854110-1-arnd@arndb.de>

On 08/01/18 12:48, Arnd Bergmann wrote:
> The bitmap_from_u32array() interface got replaced in a global
> change, but the arm_dsu_pmu driver adds another instance,
> resulting in a build failure:
> 
> drivers/perf/arm_dsu_pmu.c: In function 'dsu_pmu_probe_pmu':
> drivers/perf/arm_dsu_pmu.c:661:2: error: implicit declaration of function 'bitmap_from_u32array'; did you mean 'bitmap_from_arr32'? [-Werror=implicit-function-declaration]
> 
> This changes the new instance accordingly.
> 
> Fixes: mmotm ("bitmap: replace bitmap_{from,to}_u32array")
> Fixes: 7520fa99246d ("perf: ARM DynamIQ Shared Unit PMU support")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> The global change is currently in linux-mm, so it should be
> possible to just fold this patch into it, without causing
> extra work.
> ---
>   drivers/perf/arm_dsu_pmu.c | 6 ++----
>   1 file changed, 2 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c
> index 37c0526c93d5..e2700888a7d9 100644
> --- a/drivers/perf/arm_dsu_pmu.c
> +++ b/drivers/perf/arm_dsu_pmu.c
> @@ -658,10 +658,8 @@ static void dsu_pmu_probe_pmu(struct dsu_pmu *dsu_pmu)
>   		return;
>   	cpmceid[0] = __dsu_pmu_read_pmceid(0);
>   	cpmceid[1] = __dsu_pmu_read_pmceid(1);
> -	bitmap_from_u32array(dsu_pmu->cpmceid_bitmap,
> -				DSU_PMU_MAX_COMMON_EVENTS,
> -				cpmceid,
> -				ARRAY_SIZE(cpmceid));
> +	bitmap_from_arr32(dsu_pmu->cpmceid_bitmap, cpmceid,
> +			  DSU_PMU_MAX_COMMON_EVENTS);
>   }
>   
>   static void dsu_pmu_set_active_cpu(int cpu, struct dsu_pmu *dsu_pmu)
> 

Arnd,

Thanks for fixing this. FWIW,

Acked-by: Suzuki K Poulose <suzuki.poulose@arm.com>

^ permalink raw reply

* [PATCH v2 01/11] arm64: use RET instruction for exiting the trampoline
From: Ard Biesheuvel @ 2018-01-08 14:56 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108144534.GI25869@arm.com>

On 8 January 2018 at 14:45, Will Deacon <will.deacon@arm.com> wrote:
> On Mon, Jan 08, 2018 at 02:38:00PM +0000, Ard Biesheuvel wrote:
>> On 8 January 2018 at 14:33, Will Deacon <will.deacon@arm.com> wrote:
>> > On Sat, Jan 06, 2018 at 01:13:23PM +0000, Ard Biesheuvel wrote:
>> >> On 5 January 2018 at 13:12, Will Deacon <will.deacon@arm.com> wrote:
>> >> > Speculation attacks against the entry trampoline can potentially resteer
>> >> > the speculative instruction stream through the indirect branch and into
>> >> > arbitrary gadgets within the kernel.
>> >> >
>> >> > This patch defends against these attacks by forcing a misprediction
>> >> > through the return stack: a dummy BL instruction loads an entry into
>> >> > the stack, so that the predicted program flow of the subsequent RET
>> >> > instruction is to a branch-to-self instruction which is finally resolved
>> >> > as a branch to the kernel vectors with speculation suppressed.
>> >> >
>> >>
>> >> How safe is it to assume that every microarchitecture will behave as
>> >> expected here? Wouldn't it be safer in general not to rely on a memory
>> >> load for x30 in the first place? (see below) Or may the speculative
>> >> execution still branch anywhere even if the branch target is
>> >> guaranteed to be known by that time?
>> >
>> > The main problem with this approach is that EL0 can read out the text and
>> > find the kaslr offset.
>>
>> Not really - the CONFIG_RANDOMIZE_BASE path puts the movz/movk
>> sequence in the next page, but that does involve an unconditional
>> branch.
>
> Ah sorry, I had missed that. The unconditional branch may still be attacked,
> however.
>

Yeah, I was surprised by that. How on earth is there ever a point to
using a branch predictor to [potentially mis]predict unconditional
branches.

>> > The memory load is fine, because the data page is
>> > unmapped along with the kernel text. I'm not aware of any
>> > micro-architectures where this patch doesn't do what we need.
>> >
>>
>> Well, the memory load is what may incur the delay, creating the window
>> for speculative execution of the indirect branch. What I don't have
>> enough of a handle on is whether this speculative execution may still
>> branch to wherever the branch predictor is pointing even if the
>> register containing the branch target is already available.
>
> For the micro-architectures I'm aware of, the return stack predictor will
> always safely mispredict the jump into the kernel vectors with this patch
> applied.
>

OK, fair enough. What I am asking is really whether there is a way
where we don't have to force a misprediction, by ensuring that x30 has
assumed its final value by the time the indirect branch is
[speculatively] executed. But if unconditional branches may be
mispredicted as well, I guess this doesn't fly either.

^ permalink raw reply

* [net-next: PATCH 0/8] Armada 7k/8k PP2 ACPI support
From: Graeme Gregory @ 2018-01-08 15:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108145312.GH10940@lunn.ch>

On Mon, Jan 08, 2018 at 03:53:12PM +0100, Andrew Lunn wrote:
> On Mon, Jan 08, 2018 at 02:45:48PM +0000, Graeme Gregory wrote:
> > On Thu, Jan 04, 2018 at 05:20:36PM +0100, Andrew Lunn wrote:
> > > > > I already agreed with 'reg' being awkward in the later emails.
> > > > > Wouldn't _ADR be more appropriate to specify PHY address on MDIO bus?
> > > > > 
> > > > Ah it is an actual address, then yes _ADR is probably more appropriate.
> > > 
> > > Newbie ACPI question. What is the definition of an address?
> > > 
> > > In this cause, we are talking about an address of a device on an MDIO
> > > bus. It takes a value between 0 and 31.
> > > 
> > > How are IC2 device addresses represented in ACPI? MDIO devices and I2C
> > > devices are pretty similar. So it would make sense to use the same as
> > > what I2C uses.
> > > 
> > Too big (and has table) to sensibly quote, but defined in ACPI spec
> > 
> > 6.1.1 _ADR (Address)
> > 
> > Ive never though been quite sure if that is just an example list of
> > address types or its supposed to be canonical (in which case some ECRs
> > are needed to the spec).
> 
> Hi Graeme
> 
> I took a quick look at version 6.2, and noticed i2c devices use
> _ADR(). So using it for MDIO seems O.K.
> 
> However, i2c, spi and uart devices all seem to be described using
> GenericSerialBus. Maybe the correct way to describe MDIO devices is to
> also use GenericSerialBus?
>
I am not familiar with MDIO, but if its similar or a specific
implementation of a serial bus that does sound sane!

Graeme

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180108/2cd900b3/attachment-0001.sig>

^ permalink raw reply

* [PATCH] perf: arm_dsu_pmu: convert to bitmap_from_arr32
From: Will Deacon @ 2018-01-08 15:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <6521819f-6812-7e70-8b8d-3828992ba551@arm.com>

On Mon, Jan 08, 2018 at 02:56:24PM +0000, Suzuki K Poulose wrote:
> On 08/01/18 12:48, Arnd Bergmann wrote:
> >The bitmap_from_u32array() interface got replaced in a global
> >change, but the arm_dsu_pmu driver adds another instance,
> >resulting in a build failure:
> >
> >drivers/perf/arm_dsu_pmu.c: In function 'dsu_pmu_probe_pmu':
> >drivers/perf/arm_dsu_pmu.c:661:2: error: implicit declaration of function 'bitmap_from_u32array'; did you mean 'bitmap_from_arr32'? [-Werror=implicit-function-declaration]
> >
> >This changes the new instance accordingly.
> >
> >Fixes: mmotm ("bitmap: replace bitmap_{from,to}_u32array")
> >Fixes: 7520fa99246d ("perf: ARM DynamIQ Shared Unit PMU support")
> >Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> >---
> >The global change is currently in linux-mm, so it should be
> >possible to just fold this patch into it, without causing
> >extra work.
> >---
> >  drivers/perf/arm_dsu_pmu.c | 6 ++----
> >  1 file changed, 2 insertions(+), 4 deletions(-)
> >
> >diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c
> >index 37c0526c93d5..e2700888a7d9 100644
> >--- a/drivers/perf/arm_dsu_pmu.c
> >+++ b/drivers/perf/arm_dsu_pmu.c
> >@@ -658,10 +658,8 @@ static void dsu_pmu_probe_pmu(struct dsu_pmu *dsu_pmu)
> >  		return;
> >  	cpmceid[0] = __dsu_pmu_read_pmceid(0);
> >  	cpmceid[1] = __dsu_pmu_read_pmceid(1);
> >-	bitmap_from_u32array(dsu_pmu->cpmceid_bitmap,
> >-				DSU_PMU_MAX_COMMON_EVENTS,
> >-				cpmceid,
> >-				ARRAY_SIZE(cpmceid));
> >+	bitmap_from_arr32(dsu_pmu->cpmceid_bitmap, cpmceid,
> >+			  DSU_PMU_MAX_COMMON_EVENTS);
> >  }
> >  static void dsu_pmu_set_active_cpu(int cpu, struct dsu_pmu *dsu_pmu)
> >
> 
> Arnd,
> 
> Thanks for fixing this. FWIW,
> 
> Acked-by: Suzuki K Poulose <suzuki.poulose@arm.com>

Hmm, what's the best way to get this upstream? The PMU driver is likely to
be queued via arm64 soon, but this fixup doesn't apply there.

Will

^ permalink raw reply

* [PATCH v2 01/11] arm64: use RET instruction for exiting the trampoline
From: David Laight @ 2018-01-08 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAKv+Gu_F_hWvF7CghnDCQGCaxeViTZjvT=zqdFdD5rqdORCceQ@mail.gmail.com>

From: Ard Biesheuvel
> Sent: 08 January 2018 14:38
> To: Will Deacon
> Cc: linux-arm-kernel at lists.infradead.org; Catalin Marinas; Marc Zyngier; Lorenzo Pieralisi;
> Christoffer Dall; Linux Kernel Mailing List; Laura Abbott
> Subject: Re: [PATCH v2 01/11] arm64: use RET instruction for exiting the trampoline
> 
> On 8 January 2018 at 14:33, Will Deacon <will.deacon@arm.com> wrote:
> > On Sat, Jan 06, 2018 at 01:13:23PM +0000, Ard Biesheuvel wrote:
> >> On 5 January 2018 at 13:12, Will Deacon <will.deacon@arm.com> wrote:
> >> > Speculation attacks against the entry trampoline can potentially resteer
> >> > the speculative instruction stream through the indirect branch and into
> >> > arbitrary gadgets within the kernel.
> >> >
> >> > This patch defends against these attacks by forcing a misprediction
> >> > through the return stack: a dummy BL instruction loads an entry into
> >> > the stack, so that the predicted program flow of the subsequent RET
> >> > instruction is to a branch-to-self instruction which is finally resolved
> >> > as a branch to the kernel vectors with speculation suppressed.
> >> >
> >>
> >> How safe is it to assume that every microarchitecture will behave as
> >> expected here? Wouldn't it be safer in general not to rely on a memory
> >> load for x30 in the first place? (see below) Or may the speculative
> >> execution still branch anywhere even if the branch target is
> >> guaranteed to be known by that time?
> >
> > The main problem with this approach is that EL0 can read out the text and
> > find the kaslr offset.
> 
> Not really - the CONFIG_RANDOMIZE_BASE path puts the movz/movk
> sequence in the next page, but that does involve an unconditional
> branch.
> 
> > The memory load is fine, because the data page is
> > unmapped along with the kernel text. I'm not aware of any
> > micro-architectures where this patch doesn't do what we need.
> >
> 
> Well, the memory load is what may incur the delay, creating the window
> for speculative execution of the indirect branch. What I don't have
> enough of a handle on is whether this speculative execution may still
> branch to wherever the branch predictor is pointing even if the
> register containing the branch target is already available.

I would expect the predicted address to be used.
Much the same as a conditional branch doesn't use the flags
value at the time the instruction is decoded.

	David

^ permalink raw reply

* [PATCH 1/7] arm64: dts: marvell: use SPDX-License-Identifier for Armada SoCs
From: Gregory CLEMENT @ 2018-01-08 15:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180105153020.GF4038@lunn.ch>

Hi Andrew,
 
 On ven., janv. 05 2018, Andrew Lunn <andrew@lunn.ch> wrote:

> On Fri, Jan 05, 2018 at 03:55:55PM +0100, Gregory CLEMENT wrote:
>> Hi Andrew,
>>  
>>  On ven., janv. 05 2018, Andrew Lunn <andrew@lunn.ch> wrote:
>> 
>> >> > The previous license was GPL-2.0+ or X11, not GPL-2.0+ or MIT. Any
>> >> > reason to change from X11 to MIT ?
>> >> 
>> >> As explained in the commit log:
>> >> " the X11 license text [1] is explicitly for the X Consortium and has a
>> >> couple of extra clauses. The MIT license text [2] is actually what the
>> >> current DT files claim."
>> >> 
>> >> Also as I wrote it was already discussed on the mainling lists (device
>> >> tree one and LAKML) see:
>> >> http://lists.infradead.org/pipermail/linux-arm-kernel/2017-February/489922.html
>> >
>> > Hi Gregory
>> >
>> > If i remember correctly, there was a reason for X11 over MIT. I think
>> > Russell King looked into this. Maybe you can find the discussion on
>> > the mailing list?
>
> Hi Gregory
>
> I'm meaning an older discussion, when we first started using dual
> license. There was some discussion back then as to MIT vs X11.
> That discussion could be relevant here.

It was what I have looked for initially. But I didn't find it. I wonder
if the question was first discussed at a conference.

> What we need to be careful of is ensuring the changes you are making
> here don't actually change the licenses.  If the intent was to use
> X11, and we actually state "X11 license" in the source code, we need
> to be careful if we replace that with MIT.

I think that it the content of the text of the license show more the
intent that the title. Moreover, by using the MIT keyword on SPDX we
really have the exactly same content.

Oh and finally I found the thread:
https://www.spinics.net/lists/arm-kernel/msg358704.html

So even there the X11 license was referred as a MIT X11 license, and,
really, I don't think at any moment we intend to mention the X
Consortium for the device tree files. It was just the name "MIT license"
which was considered as ambiguous.

Gregory

>
>    Andrew

-- 
Gregory Clement, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com

^ permalink raw reply

* [PATCH v2] ARM: dts: sunxi: Add sid for a83t
From: Kyle Evans @ 2018-01-08 15:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180104140119.5pyfihp4zs2poz35@flea.lan>

On Thu, Jan 4, 2018 at 8:01 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> On Fri, Dec 22, 2017 at 06:11:52PM +0800, Chen-Yu Tsai wrote:
>> On Fri, Dec 22, 2017 at 6:07 PM, Emmanuel Vadot <manu@bidouilliste.com> wrote:
>> > On Fri, 22 Dec 2017 09:35:08 +0100
>> > Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
>> >
>> >> On Thu, Dec 21, 2017 at 07:09:03PM +0100, Emmanuel Vadot wrote:
>> >> >
>> >> >  Hi Maxime,
>> >> >
>> >> > On Thu, 21 Dec 2017 16:26:30 +0100
>> >> > Maxime Ripard <maxime.ripard@free-electrons.com> wrote:
>> >> >
>> >> > > Hi,
>> >> > >
>> >> > > On Thu, Dec 21, 2017 at 09:19:24AM -0600, Kyle Evans wrote:
>> >> > > > On Thu, Dec 21, 2017 at 8:55 AM, Maxime Ripard
>> >> > > > <maxime.ripard@free-electrons.com> wrote:
>> >> > > > > Hi Kyle,
>> >> > > > >
>> >> > > > > On Tue, Dec 19, 2017 at 03:05:23PM -0600, kevans91 at ksu.edu wrote:
>> >> > > > >> Allwinner a83t has a 1 KB sid block with efuse for security rootkey and
>> >> > > > >> thermal calibration data, add node to describe it.
>> >> > > > >>
>> >> > > > >> a83t-sid is not currently supported by nvmem/sunxi-sid, but it is
>> >> > > > >> supported in an external driver for FreeBSD.
>> >> > > > >>
>> >> > > > >> Signed-off-by: Kyle Evans <kevans91@ksu.edu>
>> >> > > > >
>> >> > > > > The patch looks fine in itself, but we've had a number of issues with
>> >> > > > > the register layout (and access patterns) in the past, so I'd rather
>> >> > > > > have something that works in Linux too if possible.
>> >> > > >
>> >> > > > I have a patch that I think should make it work fine on Linux [1], but
>> >> > > > I'm afraid I have little to no capability to test it myself and so I
>> >> > > > did not add it as well.
>> >> > > >
>> >> > > > I do know that the rootkey is offset 0x200 into the given space [2],
>> >> > > > as is the case with the H3, and that the readout quirk is not needed.
>> >> > > > I wasn't 100% sure that the a83t has 2Kbit worth of efuse space as the
>> >> > > > H3, but I do know that thermal data can be found at 0x34 and 0x38 in
>> >> > > > this space.
>> >> > >
>> >> > > Then maybe we should leave it aside until someone takes some time on
>> >> > > the A83t.
>> >> >
>> >> >  Take some time on the Linux driver and do not apply this patch for
>> >> > now you mean ?
>> >>
>> >> Yep.
>> >>
>> >> Maxime
>> >
>> >  Since linux doesn't have the compatible in it's driver what would
>> > be the harm to add the node in the DTS ? If a quirks is needed because
>> > some region is weird this would go in the driver right ? I don't see a
>> > technical problem for adding this node right now.
>> >  If Kyle confirm the lenght of the region and that no quirk is needed
>> > will it be enough ?
>>
>> I guess I wasn't very clear. I'm OK with the patch going in. The device
>> node currently says nothing about how much efuse space there is. The
>> memory region covers that and the control section, and the size matches
>> what the memory map says.
>>
>> The size and offset of the efuse space would be dealt with in the driver.
>
> Let's merge it then.
>
> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>
> Maxime

Hi,

What does the timeline for these things normally look like? I'm new to
these parts. =)

Thanks,

Kyle Evans

^ permalink raw reply

* [PATCH] perf: arm_dsu_pmu: convert to bitmap_from_arr32
From: Yury Norov @ 2018-01-08 15:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108151547.GJ25869@arm.com>

On Mon, Jan 08, 2018 at 03:15:47PM +0000, Will Deacon wrote:
> On Mon, Jan 08, 2018 at 02:56:24PM +0000, Suzuki K Poulose wrote:
> > On 08/01/18 12:48, Arnd Bergmann wrote:
> > >The bitmap_from_u32array() interface got replaced in a global
> > >change, but the arm_dsu_pmu driver adds another instance,
> > >resulting in a build failure:
> > >
> > >drivers/perf/arm_dsu_pmu.c: In function 'dsu_pmu_probe_pmu':
> > >drivers/perf/arm_dsu_pmu.c:661:2: error: implicit declaration of function 'bitmap_from_u32array'; did you mean 'bitmap_from_arr32'? [-Werror=implicit-function-declaration]
> > >
> > >This changes the new instance accordingly.
> > >
> > >Fixes: mmotm ("bitmap: replace bitmap_{from,to}_u32array")
> > >Fixes: 7520fa99246d ("perf: ARM DynamIQ Shared Unit PMU support")
> > >Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> > >---
> > >The global change is currently in linux-mm, so it should be
> > >possible to just fold this patch into it, without causing
> > >extra work.
> > >---
> > >  drivers/perf/arm_dsu_pmu.c | 6 ++----
> > >  1 file changed, 2 insertions(+), 4 deletions(-)
> > >
> > >diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c
> > >index 37c0526c93d5..e2700888a7d9 100644
> > >--- a/drivers/perf/arm_dsu_pmu.c
> > >+++ b/drivers/perf/arm_dsu_pmu.c
> > >@@ -658,10 +658,8 @@ static void dsu_pmu_probe_pmu(struct dsu_pmu *dsu_pmu)
> > >  		return;
> > >  	cpmceid[0] = __dsu_pmu_read_pmceid(0);
> > >  	cpmceid[1] = __dsu_pmu_read_pmceid(1);
> > >-	bitmap_from_u32array(dsu_pmu->cpmceid_bitmap,
> > >-				DSU_PMU_MAX_COMMON_EVENTS,
> > >-				cpmceid,
> > >-				ARRAY_SIZE(cpmceid));
> > >+	bitmap_from_arr32(dsu_pmu->cpmceid_bitmap, cpmceid,
> > >+			  DSU_PMU_MAX_COMMON_EVENTS);
> > >  }
> > >  static void dsu_pmu_set_active_cpu(int cpu, struct dsu_pmu *dsu_pmu)
> > >
> > 
> > Arnd,
> > 
> > Thanks for fixing this. FWIW,
> > 
> > Acked-by: Suzuki K Poulose <suzuki.poulose@arm.com>
> 
> Hmm, what's the best way to get this upstream? The PMU driver is likely to
> be queued via arm64 soon, but this fixup doesn't apply there.

Hi Will,

If driver will be merged in linux-next prior to my rework, I can resend
it with this patch melded. Is it OK for you?

Yury

^ permalink raw reply

* [PATCH] perf: arm_dsu_pmu: convert to bitmap_from_arr32
From: Will Deacon @ 2018-01-08 15:34 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108153225.zduqdgokcnz5k7yg@yury-thinkpad>

On Mon, Jan 08, 2018 at 06:32:25PM +0300, Yury Norov wrote:
> On Mon, Jan 08, 2018 at 03:15:47PM +0000, Will Deacon wrote:
> > On Mon, Jan 08, 2018 at 02:56:24PM +0000, Suzuki K Poulose wrote:
> > > On 08/01/18 12:48, Arnd Bergmann wrote:
> > > >The bitmap_from_u32array() interface got replaced in a global
> > > >change, but the arm_dsu_pmu driver adds another instance,
> > > >resulting in a build failure:
> > > >
> > > >drivers/perf/arm_dsu_pmu.c: In function 'dsu_pmu_probe_pmu':
> > > >drivers/perf/arm_dsu_pmu.c:661:2: error: implicit declaration of function 'bitmap_from_u32array'; did you mean 'bitmap_from_arr32'? [-Werror=implicit-function-declaration]
> > > >
> > > >This changes the new instance accordingly.
> > > >
> > > >Fixes: mmotm ("bitmap: replace bitmap_{from,to}_u32array")
> > > >Fixes: 7520fa99246d ("perf: ARM DynamIQ Shared Unit PMU support")
> > > >Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> > > >---
> > > >The global change is currently in linux-mm, so it should be
> > > >possible to just fold this patch into it, without causing
> > > >extra work.
> > > >---
> > > >  drivers/perf/arm_dsu_pmu.c | 6 ++----
> > > >  1 file changed, 2 insertions(+), 4 deletions(-)
> > > >
> > > >diff --git a/drivers/perf/arm_dsu_pmu.c b/drivers/perf/arm_dsu_pmu.c
> > > >index 37c0526c93d5..e2700888a7d9 100644
> > > >--- a/drivers/perf/arm_dsu_pmu.c
> > > >+++ b/drivers/perf/arm_dsu_pmu.c
> > > >@@ -658,10 +658,8 @@ static void dsu_pmu_probe_pmu(struct dsu_pmu *dsu_pmu)
> > > >  		return;
> > > >  	cpmceid[0] = __dsu_pmu_read_pmceid(0);
> > > >  	cpmceid[1] = __dsu_pmu_read_pmceid(1);
> > > >-	bitmap_from_u32array(dsu_pmu->cpmceid_bitmap,
> > > >-				DSU_PMU_MAX_COMMON_EVENTS,
> > > >-				cpmceid,
> > > >-				ARRAY_SIZE(cpmceid));
> > > >+	bitmap_from_arr32(dsu_pmu->cpmceid_bitmap, cpmceid,
> > > >+			  DSU_PMU_MAX_COMMON_EVENTS);
> > > >  }
> > > >  static void dsu_pmu_set_active_cpu(int cpu, struct dsu_pmu *dsu_pmu)
> > > >
> > > 
> > > Arnd,
> > > 
> > > Thanks for fixing this. FWIW,
> > > 
> > > Acked-by: Suzuki K Poulose <suzuki.poulose@arm.com>
> > 
> > Hmm, what's the best way to get this upstream? The PMU driver is likely to
> > be queued via arm64 soon, but this fixup doesn't apply there.
> 
> Hi Will,
> 
> If driver will be merged in linux-next prior to my rework, I can resend
> it with this patch melded. Is it OK for you?

Sure, as long as the arm64 pull hits mainline before the tree carrying your
rework (which probably makes sense for changes like this anyway).

Will

^ permalink raw reply

* [PATCH v6 00/16] arm64/firmware: Software Delegated Exception Interface
From: James Morse @ 2018-01-08 15:38 UTC (permalink / raw)
  To: linux-arm-kernel

This series is rebased onto arm64's kpti-base tag, with v2 of Will's kpti
series[0]. The changes were only due to code moving around, but its now
all been tested together. As before patches 15 and 16 contain the extra
kpti trampoline stuff.

The Software Delegated Exception Interface (SDEI) is an ARM specification
for registering callbacks from the platform firmware into the OS.
This is intended to be used to implement firmware-first RAS notifications,
but also supports vendor-defined events and binding IRQs as events.

The document is here:
http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_
Delegated_Exception_Interface.pdf

I anticipate once reviewed this series will go via the arm64 tree as it has
an ever closer interaction with the arch code. Despite the bulk of the code
being under /drivers/firmware/.

The relevant change in v5 was a three-way lockdep issue via the hotplug
state machine. (I argue it can't happen, but lockdep doesn't care.) Now the
hotplug callbacks save nothing, and restore the OS-view of registered/enabled.
This makes bound-interrupts harder to work with. I dropped Catalin's ack on
all affected patches.

For your regular boiler-plate cover-letter, please see [1].

Thanks,

James

[0] https://www.spinics.net/lists/arm-kernel/msg626876.html
[1] https://patchwork.ozlabs.org/cover/845290/


James Morse (16):
  KVM: arm64: Store vcpu on the stack during __guest_enter()
  KVM: arm/arm64: Convert kvm_host_cpu_state to a static per-cpu
    allocation
  KVM: arm64: Change hyp_panic()s dependency on tpidr_el2
  arm64: alternatives: use tpidr_el2 on VHE hosts
  KVM: arm64: Stop save/restoring host tpidr_el1 on VHE
  Docs: dt: add devicetree binding for describing arm64 SDEI firmware
  firmware: arm_sdei: Add driver for Software Delegated Exceptions
  arm64: Add vmap_stack header file
  arm64: uaccess: Add PAN helper
  arm64: kernel: Add arch-specific SDEI entry code and CPU masking
  firmware: arm_sdei: Add support for CPU and system power states
  firmware: arm_sdei: add support for CPU private events
  arm64: acpi: Remove __init from acpi_psci_use_hvc() for use by SDEI
  firmware: arm_sdei: Discover SDEI support via ACPI
  arm64: mmu: add the entry trampolines start/end section markers into
    sections.h
  arm64: sdei: Add trampoline code for remapping the kernel

 .../devicetree/bindings/arm/firmware/sdei.txt      |   42 +
 MAINTAINERS                                        |    9 +
 arch/arm64/include/asm/alternative.h               |    2 +
 arch/arm64/include/asm/assembler.h                 |    8 +
 arch/arm64/include/asm/kvm_host.h                  |    2 +
 arch/arm64/include/asm/mmu.h                       |    3 +-
 arch/arm64/include/asm/percpu.h                    |   11 +-
 arch/arm64/include/asm/sdei.h                      |   57 +
 arch/arm64/include/asm/sections.h                  |    1 +
 arch/arm64/include/asm/stacktrace.h                |    3 +
 arch/arm64/include/asm/uaccess.h                   |   12 +
 arch/arm64/include/asm/vmap_stack.h                |   28 +
 arch/arm64/kernel/Makefile                         |    1 +
 arch/arm64/kernel/acpi.c                           |    2 +-
 arch/arm64/kernel/alternative.c                    |    9 +-
 arch/arm64/kernel/asm-offsets.c                    |    5 +
 arch/arm64/kernel/cpufeature.c                     |   17 +
 arch/arm64/kernel/entry.S                          |  177 ++++
 arch/arm64/kernel/irq.c                            |   13 +-
 arch/arm64/kernel/sdei.c                           |  235 +++++
 arch/arm64/kernel/smp.c                            |   11 +-
 arch/arm64/kernel/suspend.c                        |    4 +-
 arch/arm64/kvm/hyp-init.S                          |    4 +
 arch/arm64/kvm/hyp/entry.S                         |   10 +-
 arch/arm64/kvm/hyp/hyp-entry.S                     |   18 +-
 arch/arm64/kvm/hyp/switch.c                        |   25 +-
 arch/arm64/kvm/hyp/sysreg-sr.c                     |   16 +-
 arch/arm64/mm/mmu.c                                |    2 -
 arch/arm64/mm/proc.S                               |    8 +
 drivers/firmware/Kconfig                           |    8 +
 drivers/firmware/Makefile                          |    1 +
 drivers/firmware/arm_sdei.c                        | 1091 ++++++++++++++++++++
 include/linux/arm_sdei.h                           |   79 ++
 include/linux/cpuhotplug.h                         |    1 +
 include/linux/psci.h                               |    3 +-
 include/uapi/linux/arm_sdei.h                      |   73 ++
 virt/kvm/arm/arm.c                                 |   18 +-
 37 files changed, 1943 insertions(+), 66 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/firmware/sdei.txt
 create mode 100644 arch/arm64/include/asm/sdei.h
 create mode 100644 arch/arm64/include/asm/vmap_stack.h
 create mode 100644 arch/arm64/kernel/sdei.c
 create mode 100644 drivers/firmware/arm_sdei.c
 create mode 100644 include/linux/arm_sdei.h
 create mode 100644 include/uapi/linux/arm_sdei.h

-- 
2.15.0

^ permalink raw reply

* [PATCH v6 01/16] KVM: arm64: Store vcpu on the stack during __guest_enter()
From: James Morse @ 2018-01-08 15:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108153818.22743-1-james.morse@arm.com>

KVM uses tpidr_el2 as its private vcpu register, which makes sense for
non-vhe world switch as only KVM can access this register. This means
vhe Linux has to use tpidr_el1, which KVM has to save/restore as part
of the host context.

If the SDEI handler code runs behind KVMs back, it mustn't access any
per-cpu variables. To allow this on systems with vhe we need to make
the host use tpidr_el2, saving KVM from save/restoring it.

__guest_enter() stores the host_ctxt on the stack, do the same with
the vcpu.

Signed-off-by: James Morse <james.morse@arm.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>
---
Changes since v2:
 * Added middle paragraph of commit message.

 arch/arm64/kvm/hyp/entry.S     | 10 +++++++---
 arch/arm64/kvm/hyp/hyp-entry.S |  6 +++---
 2 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
index 12ee62d6d410..9a8ab5dddd9e 100644
--- a/arch/arm64/kvm/hyp/entry.S
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -62,8 +62,8 @@ ENTRY(__guest_enter)
 	// Store the host regs
 	save_callee_saved_regs x1
 
-	// Store the host_ctxt for use at exit time
-	str	x1, [sp, #-16]!
+	// Store host_ctxt and vcpu for use at exit time
+	stp	x1, x0, [sp, #-16]!
 
 	add	x18, x0, #VCPU_CONTEXT
 
@@ -159,6 +159,10 @@ abort_guest_exit_end:
 ENDPROC(__guest_exit)
 
 ENTRY(__fpsimd_guest_restore)
+	// x0: esr
+	// x1: vcpu
+	// x2-x29,lr: vcpu regs
+	// vcpu x0-x1 on the stack
 	stp	x2, x3, [sp, #-16]!
 	stp	x4, lr, [sp, #-16]!
 
@@ -173,7 +177,7 @@ alternative_else
 alternative_endif
 	isb
 
-	mrs	x3, tpidr_el2
+	mov	x3, x1
 
 	ldr	x0, [x3, #VCPU_HOST_CONTEXT]
 	kern_hyp_va x0
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index 5170ce1021da..fce7cc507e0a 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -104,6 +104,7 @@ el1_trap:
 	/*
 	 * x0: ESR_EC
 	 */
+	ldr	x1, [sp, #16 + 8]	// vcpu stored by __guest_enter
 
 	/*
 	 * We trap the first access to the FP/SIMD to save the host context
@@ -116,19 +117,18 @@ alternative_if_not ARM64_HAS_NO_FPSIMD
 	b.eq	__fpsimd_guest_restore
 alternative_else_nop_endif
 
-	mrs	x1, tpidr_el2
 	mov	x0, #ARM_EXCEPTION_TRAP
 	b	__guest_exit
 
 el1_irq:
 	stp     x0, x1, [sp, #-16]!
-	mrs	x1, tpidr_el2
+	ldr	x1, [sp, #16 + 8]
 	mov	x0, #ARM_EXCEPTION_IRQ
 	b	__guest_exit
 
 el1_error:
 	stp     x0, x1, [sp, #-16]!
-	mrs	x1, tpidr_el2
+	ldr	x1, [sp, #16 + 8]
 	mov	x0, #ARM_EXCEPTION_EL1_SERROR
 	b	__guest_exit
 
-- 
2.15.0

^ permalink raw reply related

* [PATCH v6 02/16] KVM: arm/arm64: Convert kvm_host_cpu_state to a static per-cpu allocation
From: James Morse @ 2018-01-08 15:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108153818.22743-1-james.morse@arm.com>

kvm_host_cpu_state is a per-cpu allocation made from kvm_arch_init()
used to store the host EL1 registers when KVM switches to a guest.

Make it easier for ASM to generate pointers into this per-cpu memory
by making it a static allocation.

Signed-off-by: James Morse <james.morse@arm.com>
Acked-by: Christoffer Dall <cdall@linaro.org>
---
 virt/kvm/arm/arm.c | 18 +++---------------
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
index 1c9fdb6db124..a58e2c4c5735 100644
--- a/virt/kvm/arm/arm.c
+++ b/virt/kvm/arm/arm.c
@@ -53,8 +53,8 @@
 __asm__(".arch_extension	virt");
 #endif
 
+DEFINE_PER_CPU(kvm_cpu_context_t, kvm_host_cpu_state);
 static DEFINE_PER_CPU(unsigned long, kvm_arm_hyp_stack_page);
-static kvm_cpu_context_t __percpu *kvm_host_cpu_state;
 
 /* Per-CPU variable containing the currently running vcpu. */
 static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_arm_running_vcpu);
@@ -354,7 +354,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 	}
 
 	vcpu->cpu = cpu;
-	vcpu->arch.host_cpu_context = this_cpu_ptr(kvm_host_cpu_state);
+	vcpu->arch.host_cpu_context = this_cpu_ptr(&kvm_host_cpu_state);
 
 	kvm_arm_set_running_vcpu(vcpu);
 	kvm_vgic_load(vcpu);
@@ -1272,19 +1272,8 @@ static inline void hyp_cpu_pm_exit(void)
 }
 #endif
 
-static void teardown_common_resources(void)
-{
-	free_percpu(kvm_host_cpu_state);
-}
-
 static int init_common_resources(void)
 {
-	kvm_host_cpu_state = alloc_percpu(kvm_cpu_context_t);
-	if (!kvm_host_cpu_state) {
-		kvm_err("Cannot allocate host CPU state\n");
-		return -ENOMEM;
-	}
-
 	/* set size of VMID supported by CPU */
 	kvm_vmid_bits = kvm_get_vmid_bits();
 	kvm_info("%d-bit VMID\n", kvm_vmid_bits);
@@ -1426,7 +1415,7 @@ static int init_hyp_mode(void)
 	for_each_possible_cpu(cpu) {
 		kvm_cpu_context_t *cpu_ctxt;
 
-		cpu_ctxt = per_cpu_ptr(kvm_host_cpu_state, cpu);
+		cpu_ctxt = per_cpu_ptr(&kvm_host_cpu_state, cpu);
 		err = create_hyp_mappings(cpu_ctxt, cpu_ctxt + 1, PAGE_HYP);
 
 		if (err) {
@@ -1550,7 +1539,6 @@ int kvm_arch_init(void *opaque)
 	if (!in_hyp_mode)
 		teardown_hyp_mode();
 out_err:
-	teardown_common_resources();
 	return err;
 }
 
-- 
2.15.0

^ permalink raw reply related

* [PATCH v6 03/16] KVM: arm64: Change hyp_panic()s dependency on tpidr_el2
From: James Morse @ 2018-01-08 15:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108153818.22743-1-james.morse@arm.com>

Make tpidr_el2 a cpu-offset for per-cpu variables in the same way the
host uses tpidr_el1. This lets tpidr_el{1,2} have the same value, and
on VHE they can be the same register.

KVM calls hyp_panic() when anything unexpected happens. This may occur
while a guest owns the EL1 registers. KVM stashes the vcpu pointer in
tpidr_el2, which it uses to find the host context in order to restore
the host EL1 registers before parachuting into the host's panic().

The host context is a struct kvm_cpu_context allocated in the per-cpu
area, and mapped to hyp. Given the per-cpu offset for this CPU, this is
easy to find. Change hyp_panic() to take a pointer to the
struct kvm_cpu_context. Wrap these calls with an asm function that
retrieves the struct kvm_cpu_context from the host's per-cpu area.

Copy the per-cpu offset from the hosts tpidr_el1 into tpidr_el2 during
kvm init. (Later patches will make this unnecessary for VHE hosts)

We print out the vcpu pointer as part of the panic message. Add a back
reference to the 'running vcpu' in the host cpu context to preserve this.

Signed-off-by: James Morse <james.morse@arm.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>
---
Changes since v1:
 * Added a comment explaining how =kvm_host_cpu_state gets from a host-va
   to a hyp va.
 * Added the first paragraph to the commit message.

 arch/arm64/include/asm/kvm_host.h |  2 ++
 arch/arm64/kvm/hyp/hyp-entry.S    | 12 ++++++++++++
 arch/arm64/kvm/hyp/s2-setup.c     |  3 +++
 arch/arm64/kvm/hyp/switch.c       | 25 +++++++++++++------------
 4 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index ea6cb5b24258..7ee72b402907 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -192,6 +192,8 @@ struct kvm_cpu_context {
 		u64 sys_regs[NR_SYS_REGS];
 		u32 copro[NR_COPRO_REGS];
 	};
+
+	struct kvm_vcpu *__hyp_running_vcpu;
 };
 
 typedef struct kvm_cpu_context kvm_cpu_context_t;
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index fce7cc507e0a..e4f37b9dd47c 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -163,6 +163,18 @@ ENTRY(__hyp_do_panic)
 	eret
 ENDPROC(__hyp_do_panic)
 
+ENTRY(__hyp_panic)
+	/*
+	 * '=kvm_host_cpu_state' is a host VA from the constant pool, it may
+	 * not be accessible by this address from EL2, hyp_panic() converts
+	 * it with kern_hyp_va() before use.
+	 */
+	ldr	x0, =kvm_host_cpu_state
+	mrs	x1, tpidr_el2
+	add	x0, x0, x1
+	b	hyp_panic
+ENDPROC(__hyp_panic)
+
 .macro invalid_vector	label, target = __hyp_panic
 	.align	2
 \label:
diff --git a/arch/arm64/kvm/hyp/s2-setup.c b/arch/arm64/kvm/hyp/s2-setup.c
index a81f5e10fc8c..7fb88274eba1 100644
--- a/arch/arm64/kvm/hyp/s2-setup.c
+++ b/arch/arm64/kvm/hyp/s2-setup.c
@@ -84,5 +84,8 @@ u32 __hyp_text __init_stage2_translation(void)
 
 	write_sysreg(val, vtcr_el2);
 
+	/* copy tpidr_el1 into tpidr_el2 for use by HYP */
+	write_sysreg(read_sysreg(tpidr_el1), tpidr_el2);
+
 	return parange;
 }
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 4d273f6d0e69..4d83c69bafba 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -306,9 +306,9 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 	u64 exit_code;
 
 	vcpu = kern_hyp_va(vcpu);
-	write_sysreg(vcpu, tpidr_el2);
 
 	host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+	host_ctxt->__hyp_running_vcpu = vcpu;
 	guest_ctxt = &vcpu->arch.ctxt;
 
 	__sysreg_save_host_state(host_ctxt);
@@ -435,7 +435,8 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
 
 static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n";
 
-static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par)
+static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par,
+					     struct kvm_vcpu *vcpu)
 {
 	unsigned long str_va;
 
@@ -449,35 +450,35 @@ static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par)
 	__hyp_do_panic(str_va,
 		       spsr,  elr,
 		       read_sysreg(esr_el2),   read_sysreg_el2(far),
-		       read_sysreg(hpfar_el2), par,
-		       (void *)read_sysreg(tpidr_el2));
+		       read_sysreg(hpfar_el2), par, vcpu);
 }
 
-static void __hyp_text __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par)
+static void __hyp_text __hyp_call_panic_vhe(u64 spsr, u64 elr, u64 par,
+					    struct kvm_vcpu *vcpu)
 {
 	panic(__hyp_panic_string,
 	      spsr,  elr,
 	      read_sysreg_el2(esr),   read_sysreg_el2(far),
-	      read_sysreg(hpfar_el2), par,
-	      (void *)read_sysreg(tpidr_el2));
+	      read_sysreg(hpfar_el2), par, vcpu);
 }
 
 static hyp_alternate_select(__hyp_call_panic,
 			    __hyp_call_panic_nvhe, __hyp_call_panic_vhe,
 			    ARM64_HAS_VIRT_HOST_EXTN);
 
-void __hyp_text __noreturn __hyp_panic(void)
+void __hyp_text __noreturn hyp_panic(struct kvm_cpu_context *__host_ctxt)
 {
+	struct kvm_vcpu *vcpu = NULL;
+
 	u64 spsr = read_sysreg_el2(spsr);
 	u64 elr = read_sysreg_el2(elr);
 	u64 par = read_sysreg(par_el1);
 
 	if (read_sysreg(vttbr_el2)) {
-		struct kvm_vcpu *vcpu;
 		struct kvm_cpu_context *host_ctxt;
 
-		vcpu = (struct kvm_vcpu *)read_sysreg(tpidr_el2);
-		host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+		host_ctxt = kern_hyp_va(__host_ctxt);
+		vcpu = host_ctxt->__hyp_running_vcpu;
 		__timer_disable_traps(vcpu);
 		__deactivate_traps(vcpu);
 		__deactivate_vm(vcpu);
@@ -485,7 +486,7 @@ void __hyp_text __noreturn __hyp_panic(void)
 	}
 
 	/* Call panic for real */
-	__hyp_call_panic()(spsr, elr, par);
+	__hyp_call_panic()(spsr, elr, par, vcpu);
 
 	unreachable();
 }
-- 
2.15.0

^ permalink raw reply related

* [PATCH v6 04/16] arm64: alternatives: use tpidr_el2 on VHE hosts
From: James Morse @ 2018-01-08 15:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108153818.22743-1-james.morse@arm.com>

Now that KVM uses tpidr_el2 in the same way as Linux's cpu_offset in
tpidr_el1, merge the two. This saves KVM from save/restoring tpidr_el1
on VHE hosts, and allows future code to blindly access per-cpu variables
without triggering world-switch.

Signed-off-by: James Morse <james.morse@arm.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
---
Changes since v3:
 * Moved 'alternatives_applied' test all into C,
 * Made enable method static and dragged up before first-use.

Changes since v1:
 * cpu_copy_el2regs()'s 'have I been patched' test now always sets a register,
   just in case the compiler optimises out part of the logic.

 arch/arm64/include/asm/alternative.h |  2 ++
 arch/arm64/include/asm/assembler.h   |  8 ++++++++
 arch/arm64/include/asm/percpu.h      | 11 +++++++++--
 arch/arm64/kernel/alternative.c      |  9 +++++----
 arch/arm64/kernel/cpufeature.c       | 17 +++++++++++++++++
 arch/arm64/mm/proc.S                 |  8 ++++++++
 6 files changed, 49 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h
index 4a85c6952a22..669028172fd6 100644
--- a/arch/arm64/include/asm/alternative.h
+++ b/arch/arm64/include/asm/alternative.h
@@ -12,6 +12,8 @@
 #include <linux/stddef.h>
 #include <linux/stringify.h>
 
+extern int alternatives_applied;
+
 struct alt_instr {
 	s32 orig_offset;	/* offset to original instruction */
 	s32 alt_offset;		/* offset to replacement instruction */
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index cee60ce0da52..26ccee193d62 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -254,7 +254,11 @@ lr	.req	x30		// link register
 #else
 	adr_l	\dst, \sym
 #endif
+alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
 	mrs	\tmp, tpidr_el1
+alternative_else
+	mrs	\tmp, tpidr_el2
+alternative_endif
 	add	\dst, \dst, \tmp
 	.endm
 
@@ -265,7 +269,11 @@ lr	.req	x30		// link register
 	 */
 	.macro ldr_this_cpu dst, sym, tmp
 	adr_l	\dst, \sym
+alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
 	mrs	\tmp, tpidr_el1
+alternative_else
+	mrs	\tmp, tpidr_el2
+alternative_endif
 	ldr	\dst, [\dst, \tmp]
 	.endm
 
diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h
index 3bd498e4de4c..43393208229e 100644
--- a/arch/arm64/include/asm/percpu.h
+++ b/arch/arm64/include/asm/percpu.h
@@ -16,11 +16,15 @@
 #ifndef __ASM_PERCPU_H
 #define __ASM_PERCPU_H
 
+#include <asm/alternative.h>
 #include <asm/stack_pointer.h>
 
 static inline void set_my_cpu_offset(unsigned long off)
 {
-	asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory");
+	asm volatile(ALTERNATIVE("msr tpidr_el1, %0",
+				 "msr tpidr_el2, %0",
+				 ARM64_HAS_VIRT_HOST_EXTN)
+			:: "r" (off) : "memory");
 }
 
 static inline unsigned long __my_cpu_offset(void)
@@ -31,7 +35,10 @@ static inline unsigned long __my_cpu_offset(void)
 	 * We want to allow caching the value, so avoid using volatile and
 	 * instead use a fake stack read to hazard against barrier().
 	 */
-	asm("mrs %0, tpidr_el1" : "=r" (off) :
+	asm(ALTERNATIVE("mrs %0, tpidr_el1",
+			"mrs %0, tpidr_el2",
+			ARM64_HAS_VIRT_HOST_EXTN)
+		: "=r" (off) :
 		"Q" (*(const unsigned long *)current_stack_pointer));
 
 	return off;
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
index 6dd0a3a3e5c9..414288a558c8 100644
--- a/arch/arm64/kernel/alternative.c
+++ b/arch/arm64/kernel/alternative.c
@@ -32,6 +32,8 @@
 #define ALT_ORIG_PTR(a)		__ALT_PTR(a, orig_offset)
 #define ALT_REPL_PTR(a)		__ALT_PTR(a, alt_offset)
 
+int alternatives_applied;
+
 struct alt_region {
 	struct alt_instr *begin;
 	struct alt_instr *end;
@@ -143,7 +145,6 @@ static void __apply_alternatives(void *alt_region, bool use_linear_alias)
  */
 static int __apply_alternatives_multi_stop(void *unused)
 {
-	static int patched = 0;
 	struct alt_region region = {
 		.begin	= (struct alt_instr *)__alt_instructions,
 		.end	= (struct alt_instr *)__alt_instructions_end,
@@ -151,14 +152,14 @@ static int __apply_alternatives_multi_stop(void *unused)
 
 	/* We always have a CPU 0 at this point (__init) */
 	if (smp_processor_id()) {
-		while (!READ_ONCE(patched))
+		while (!READ_ONCE(alternatives_applied))
 			cpu_relax();
 		isb();
 	} else {
-		BUG_ON(patched);
+		BUG_ON(alternatives_applied);
 		__apply_alternatives(&region, true);
 		/* Barriers provided by the cache flushing */
-		WRITE_ONCE(patched, 1);
+		WRITE_ONCE(alternatives_applied, 1);
 	}
 
 	return 0;
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 9d4d82c11528..501cd1aff82c 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -885,6 +885,22 @@ static int __init parse_kpti(char *str)
 __setup("kpti=", parse_kpti);
 #endif	/* CONFIG_UNMAP_KERNEL_AT_EL0 */
 
+static int cpu_copy_el2regs(void *__unused)
+{
+	/*
+	 * Copy register values that aren't redirected by hardware.
+	 *
+	 * Before code patching, we only set tpidr_el1, all CPUs need to copy
+	 * this value to tpidr_el2 before we patch the code. Once we've done
+	 * that, freshly-onlined CPUs will set tpidr_el2, so we don't need to
+	 * do anything here.
+	 */
+	if (!alternatives_applied)
+		write_sysreg(read_sysreg(tpidr_el1), tpidr_el2);
+
+	return 0;
+}
+
 static const struct arm64_cpu_capabilities arm64_features[] = {
 	{
 		.desc = "GIC system register CPU interface",
@@ -954,6 +970,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
 		.capability = ARM64_HAS_VIRT_HOST_EXTN,
 		.def_scope = SCOPE_SYSTEM,
 		.matches = runs_at_el2,
+		.enable = cpu_copy_el2regs,
 	},
 	{
 		.desc = "32-bit EL0 Support",
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index 6affb68a9a14..f1635301c16e 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -70,7 +70,11 @@ ENTRY(cpu_do_suspend)
 	mrs	x8, mdscr_el1
 	mrs	x9, oslsr_el1
 	mrs	x10, sctlr_el1
+alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
 	mrs	x11, tpidr_el1
+alternative_else
+	mrs	x11, tpidr_el2
+alternative_endif
 	mrs	x12, sp_el0
 	stp	x2, x3, [x0]
 	stp	x4, xzr, [x0, #16]
@@ -116,7 +120,11 @@ ENTRY(cpu_do_resume)
 	msr	mdscr_el1, x10
 
 	msr	sctlr_el1, x12
+alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
 	msr	tpidr_el1, x13
+alternative_else
+	msr	tpidr_el2, x13
+alternative_endif
 	msr	sp_el0, x14
 	/*
 	 * Restore oslsr_el1 by writing oslar_el1
-- 
2.15.0

^ permalink raw reply related

* [PATCH v6 05/16] KVM: arm64: Stop save/restoring host tpidr_el1 on VHE
From: James Morse @ 2018-01-08 15:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108153818.22743-1-james.morse@arm.com>

Now that a VHE host uses tpidr_el2 for the cpu offset we no longer
need KVM to save/restore tpidr_el1. Move this from the 'common' code
into the non-vhe code. While we're at it, on VHE we don't need to
save the ELR or SPSR as kernel_entry in entry.S will have pushed these
onto the kernel stack, and will restore them from there. Move these
to the non-vhe code as we need them to get back to the host.

Finally remove the always-copy-tpidr we hid in the stage2 setup
code, cpufeature's enable callback will do this for VHE, we only
need KVM to do it for non-vhe. Add the copy into kvm-init instead.

Signed-off-by: James Morse <james.morse@arm.com>
Reviewed-by: Christoffer Dall <cdall@linaro.org>
---
Changes since v1:
 * Switched KVM<->arm64 in the subject.

 arch/arm64/kvm/hyp-init.S      |  4 ++++
 arch/arm64/kvm/hyp/s2-setup.c  |  3 ---
 arch/arm64/kvm/hyp/sysreg-sr.c | 16 ++++++++--------
 3 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S
index 3f9615582377..fbf259893f6a 100644
--- a/arch/arm64/kvm/hyp-init.S
+++ b/arch/arm64/kvm/hyp-init.S
@@ -122,6 +122,10 @@ CPU_BE(	orr	x4, x4, #SCTLR_ELx_EE)
 	kern_hyp_va	x2
 	msr	vbar_el2, x2
 
+	/* copy tpidr_el1 into tpidr_el2 for use by HYP */
+	mrs	x1, tpidr_el1
+	msr	tpidr_el2, x1
+
 	/* Hello, World! */
 	eret
 ENDPROC(__kvm_hyp_init)
diff --git a/arch/arm64/kvm/hyp/s2-setup.c b/arch/arm64/kvm/hyp/s2-setup.c
index 7fb88274eba1..a81f5e10fc8c 100644
--- a/arch/arm64/kvm/hyp/s2-setup.c
+++ b/arch/arm64/kvm/hyp/s2-setup.c
@@ -84,8 +84,5 @@ u32 __hyp_text __init_stage2_translation(void)
 
 	write_sysreg(val, vtcr_el2);
 
-	/* copy tpidr_el1 into tpidr_el2 for use by HYP */
-	write_sysreg(read_sysreg(tpidr_el1), tpidr_el2);
-
 	return parange;
 }
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
index 934137647837..c54cc2afb92b 100644
--- a/arch/arm64/kvm/hyp/sysreg-sr.c
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -27,8 +27,8 @@ static void __hyp_text __sysreg_do_nothing(struct kvm_cpu_context *ctxt) { }
 /*
  * Non-VHE: Both host and guest must save everything.
  *
- * VHE: Host must save tpidr*_el[01], actlr_el1, mdscr_el1, sp0, pc,
- * pstate, and guest must save everything.
+ * VHE: Host must save tpidr*_el0, actlr_el1, mdscr_el1, sp_el0,
+ * and guest must save everything.
  */
 
 static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
@@ -36,11 +36,8 @@ static void __hyp_text __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
 	ctxt->sys_regs[ACTLR_EL1]	= read_sysreg(actlr_el1);
 	ctxt->sys_regs[TPIDR_EL0]	= read_sysreg(tpidr_el0);
 	ctxt->sys_regs[TPIDRRO_EL0]	= read_sysreg(tpidrro_el0);
-	ctxt->sys_regs[TPIDR_EL1]	= read_sysreg(tpidr_el1);
 	ctxt->sys_regs[MDSCR_EL1]	= read_sysreg(mdscr_el1);
 	ctxt->gp_regs.regs.sp		= read_sysreg(sp_el0);
-	ctxt->gp_regs.regs.pc		= read_sysreg_el2(elr);
-	ctxt->gp_regs.regs.pstate	= read_sysreg_el2(spsr);
 }
 
 static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
@@ -62,10 +59,13 @@ static void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
 	ctxt->sys_regs[AMAIR_EL1]	= read_sysreg_el1(amair);
 	ctxt->sys_regs[CNTKCTL_EL1]	= read_sysreg_el1(cntkctl);
 	ctxt->sys_regs[PAR_EL1]		= read_sysreg(par_el1);
+	ctxt->sys_regs[TPIDR_EL1]	= read_sysreg(tpidr_el1);
 
 	ctxt->gp_regs.sp_el1		= read_sysreg(sp_el1);
 	ctxt->gp_regs.elr_el1		= read_sysreg_el1(elr);
 	ctxt->gp_regs.spsr[KVM_SPSR_EL1]= read_sysreg_el1(spsr);
+	ctxt->gp_regs.regs.pc		= read_sysreg_el2(elr);
+	ctxt->gp_regs.regs.pstate	= read_sysreg_el2(spsr);
 }
 
 static hyp_alternate_select(__sysreg_call_save_host_state,
@@ -89,11 +89,8 @@ static void __hyp_text __sysreg_restore_common_state(struct kvm_cpu_context *ctx
 	write_sysreg(ctxt->sys_regs[ACTLR_EL1],	  actlr_el1);
 	write_sysreg(ctxt->sys_regs[TPIDR_EL0],	  tpidr_el0);
 	write_sysreg(ctxt->sys_regs[TPIDRRO_EL0], tpidrro_el0);
-	write_sysreg(ctxt->sys_regs[TPIDR_EL1],	  tpidr_el1);
 	write_sysreg(ctxt->sys_regs[MDSCR_EL1],	  mdscr_el1);
 	write_sysreg(ctxt->gp_regs.regs.sp,	  sp_el0);
-	write_sysreg_el2(ctxt->gp_regs.regs.pc,	  elr);
-	write_sysreg_el2(ctxt->gp_regs.regs.pstate, spsr);
 }
 
 static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
@@ -115,10 +112,13 @@ static void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
 	write_sysreg_el1(ctxt->sys_regs[AMAIR_EL1],	amair);
 	write_sysreg_el1(ctxt->sys_regs[CNTKCTL_EL1], 	cntkctl);
 	write_sysreg(ctxt->sys_regs[PAR_EL1],		par_el1);
+	write_sysreg(ctxt->sys_regs[TPIDR_EL1],		tpidr_el1);
 
 	write_sysreg(ctxt->gp_regs.sp_el1,		sp_el1);
 	write_sysreg_el1(ctxt->gp_regs.elr_el1,		elr);
 	write_sysreg_el1(ctxt->gp_regs.spsr[KVM_SPSR_EL1],spsr);
+	write_sysreg_el2(ctxt->gp_regs.regs.pc,		elr);
+	write_sysreg_el2(ctxt->gp_regs.regs.pstate,	spsr);
 }
 
 static hyp_alternate_select(__sysreg_call_restore_host_state,
-- 
2.15.0

^ permalink raw reply related

* [PATCH v6 06/16] Docs: dt: add devicetree binding for describing arm64 SDEI firmware
From: James Morse @ 2018-01-08 15:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108153818.22743-1-james.morse@arm.com>

The Software Delegated Exception Interface (SDEI) is an ARM standard
for registering callbacks from the platform firmware into the OS.
This is typically used to implement RAS notifications, or from an
IRQ that has been promoted to a firmware-assisted NMI.

Add a new devicetree binding to describe the SDE firmware interface.

Signed-off-by: James Morse <james.morse@arm.com>
Acked-by: Rob Herring <robh@kernel.org>
---
Changes since v2:
 * Added Rob's Ack
 * Fixed 'childe node' typo

Changes since v1:
* Added bound IRQ description for binding,
* Reference SMC-CC, not 'AAPCS like'
* Move sdei node under firmware node (and the file path)

 .../devicetree/bindings/arm/firmware/sdei.txt      | 42 ++++++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/firmware/sdei.txt

diff --git a/Documentation/devicetree/bindings/arm/firmware/sdei.txt b/Documentation/devicetree/bindings/arm/firmware/sdei.txt
new file mode 100644
index 000000000000..ee3f0ff49889
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/firmware/sdei.txt
@@ -0,0 +1,42 @@
+* Software Delegated Exception Interface (SDEI)
+
+Firmware implementing the SDEI functions described in ARM document number
+ARM DEN 0054A ("Software Delegated Exception Interface") can be used by
+Linux to receive notification of events such as those generated by
+firmware-first error handling, or from an IRQ that has been promoted to
+a firmware-assisted NMI.
+
+The interface provides a number of API functions for registering callbacks
+and enabling/disabling events. Functions are invoked by trapping to the
+privilege level of the SDEI firmware (specified as part of the binding
+below) and passing arguments in a manner specified by the "SMC Calling
+Convention (ARM DEN 0028B):
+
+	 r0		=> 32-bit Function ID / return value
+	{r1 - r3}	=> Parameters
+
+Note that the immediate field of the trapping instruction must be set
+to #0.
+
+The SDEI_EVENT_REGISTER function registers a callback in the kernel
+text to handle the specified event number.
+
+The sdei node should be a child node of '/firmware' and have required
+properties:
+
+ - compatible    : should contain:
+	* "arm,sdei-1.0" : For implementations complying to SDEI version 1.x.
+
+ - method        : The method of calling the SDEI firmware. Permitted
+                   values are:
+	* "smc" : SMC #0, with the register assignments specified in this
+	          binding.
+	* "hvc" : HVC #0, with the register assignments specified in this
+	          binding.
+Example:
+	firmware {
+		sdei {
+			compatible	= "arm,sdei-1.0";
+			method		= "smc";
+		};
+	};
-- 
2.15.0

^ permalink raw reply related

* [PATCH v6 07/16] firmware: arm_sdei: Add driver for Software Delegated Exceptions
From: James Morse @ 2018-01-08 15:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108153818.22743-1-james.morse@arm.com>

The Software Delegated Exception Interface (SDEI) is an ARM standard
for registering callbacks from the platform firmware into the OS.
This is typically used to implement firmware notifications (such as
firmware-first RAS) or promote an IRQ that has been promoted to a
firmware-assisted NMI.

Add the code for detecting the SDEI version and the framework for
registering and unregistering events. Subsequent patches will add the
arch-specific backend code and the necessary power management hooks.

Only shared events are supported, power management, private events and
discovery for ACPI systems will be added by later patches.

Signed-off-by: James Morse <james.morse@arm.com>
---
Changes since v4:
 * Ripped out passed in gfp_t, it was masking a bug, all allocations are now
   GFP_KERNEL.
 * Switched spin_lock for a mutex and added a spin_lock around the list, this
   fixes the bug and makes a later cpu-hotplug interaction easier.
 * Dropped Catalin's ack

Changes since v3:
 * Depend on arm64 from the beginning, add a placeholder arch asm file.
 * Added MAINTAINER record
 * Renamed sdei.h files to arm_sdei.h
 * Removed IS_SDEI_CALL(), KVM won't need this...

 MAINTAINERS                   |   9 +
 arch/arm64/include/asm/sdei.h |   8 +
 drivers/firmware/Kconfig      |   8 +
 drivers/firmware/Makefile     |   1 +
 drivers/firmware/arm_sdei.c   | 619 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/arm_sdei.h      |  79 ++++++
 include/uapi/linux/arm_sdei.h |  73 +++++
 7 files changed, 797 insertions(+)
 create mode 100644 arch/arm64/include/asm/sdei.h
 create mode 100644 drivers/firmware/arm_sdei.c
 create mode 100644 include/linux/arm_sdei.h
 create mode 100644 include/uapi/linux/arm_sdei.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 82ad0eabce4f..c06885c4c0f1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -12618,6 +12618,15 @@ L:	linux-media at vger.kernel.org
 S:	Supported
 F:	drivers/media/pci/solo6x10/
 
+SOFTWARE DELEGATED EXCEPTION INTERFACE (SDEI)
+M:	James Morse <james.morse@arm.com>
+L:	linux-arm-kernel at lists.infradead.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/arm/firmware/sdei.txt
+F:	drivers/firmware/arm_sdei.c
+F:	include/linux/sdei.h
+F:	include/uapi/linux/sdei.h
+
 SOFTWARE RAID (Multiple Disks) SUPPORT
 M:	Shaohua Li <shli@kernel.org>
 L:	linux-raid at vger.kernel.org
diff --git a/arch/arm64/include/asm/sdei.h b/arch/arm64/include/asm/sdei.h
new file mode 100644
index 000000000000..59f26b6e673d
--- /dev/null
+++ b/arch/arm64/include/asm/sdei.h
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2017 Arm Ltd.
+#ifndef __ASM_SDEI_H
+#define __ASM_SDEI_H
+
+/* Later patches add the arch specific bits */
+
+#endif /* __ASM_SDEI_H */
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index fa87a055905e..e77f77caa0f3 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -48,6 +48,14 @@ config ARM_SCPI_POWER_DOMAIN
 	  This enables support for the SCPI power domains which can be
 	  enabled or disabled via the SCP firmware
 
+config ARM_SDE_INTERFACE
+	bool "ARM Software Delegated Exception Interface (SDEI)"
+	depends on ARM64
+	help
+	  The Software Delegated Exception Interface (SDEI) is an ARM
+	  standard for registering callbacks from the platform firmware
+	  into the OS. This is typically used to implement RAS notifications.
+
 config EDD
 	tristate "BIOS Enhanced Disk Drive calls determine boot disk"
 	depends on X86
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index feaa890197f3..b248238ddc6a 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_ARM_PSCI_FW)	+= psci.o
 obj-$(CONFIG_ARM_PSCI_CHECKER)	+= psci_checker.o
 obj-$(CONFIG_ARM_SCPI_PROTOCOL)	+= arm_scpi.o
 obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o
+obj-$(CONFIG_ARM_SDE_INTERFACE)	+= arm_sdei.o
 obj-$(CONFIG_DMI)		+= dmi_scan.o
 obj-$(CONFIG_DMI_SYSFS)		+= dmi-sysfs.o
 obj-$(CONFIG_EDD)		+= edd.o
diff --git a/drivers/firmware/arm_sdei.c b/drivers/firmware/arm_sdei.c
new file mode 100644
index 000000000000..8da173cc7e43
--- /dev/null
+++ b/drivers/firmware/arm_sdei.c
@@ -0,0 +1,619 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2017 Arm Ltd.
+#define pr_fmt(fmt) "sdei: " fmt
+
+#include <linux/acpi.h>
+#include <linux/arm_sdei.h>
+#include <linux/arm-smccc.h>
+#include <linux/bitops.h>
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/hardirq.h>
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/kvm_host.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/percpu.h>
+#include <linux/platform_device.h>
+#include <linux/ptrace.h>
+#include <linux/preempt.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+
+/*
+ * The call to use to reach the firmware.
+ */
+static asmlinkage void (*sdei_firmware_call)(unsigned long function_id,
+		      unsigned long arg0, unsigned long arg1,
+		      unsigned long arg2, unsigned long arg3,
+		      unsigned long arg4, struct arm_smccc_res *res);
+
+/* entry point from firmware to arch asm code */
+static unsigned long sdei_entry_point;
+
+struct sdei_event {
+	struct list_head	list;
+	u32			event_num;
+	u8			type;
+	u8			priority;
+
+	/* This pointer is handed to firmware as the event argument. */
+	struct sdei_registered_event *registered;
+};
+
+/* Take the mutex for any API call or modification. Take the mutex first. */
+static DEFINE_MUTEX(sdei_events_lock);
+
+/* and then hold this when modifying the list */
+static DEFINE_SPINLOCK(sdei_list_lock);
+static LIST_HEAD(sdei_list);
+
+static int sdei_to_linux_errno(unsigned long sdei_err)
+{
+	switch (sdei_err) {
+	case SDEI_NOT_SUPPORTED:
+		return -EOPNOTSUPP;
+	case SDEI_INVALID_PARAMETERS:
+		return -EINVAL;
+	case SDEI_DENIED:
+		return -EPERM;
+	case SDEI_PENDING:
+		return -EINPROGRESS;
+	case SDEI_OUT_OF_RESOURCE:
+		return -ENOMEM;
+	}
+
+	/* Not an error value ... */
+	return sdei_err;
+}
+
+/*
+ * If x0 is any of these values, then the call failed, use sdei_to_linux_errno()
+ * to translate.
+ */
+static int sdei_is_err(struct arm_smccc_res *res)
+{
+	switch (res->a0) {
+	case SDEI_NOT_SUPPORTED:
+	case SDEI_INVALID_PARAMETERS:
+	case SDEI_DENIED:
+	case SDEI_PENDING:
+	case SDEI_OUT_OF_RESOURCE:
+		return true;
+	}
+
+	return false;
+}
+
+static int invoke_sdei_fn(unsigned long function_id, unsigned long arg0,
+			  unsigned long arg1, unsigned long arg2,
+			  unsigned long arg3, unsigned long arg4,
+			  u64 *result)
+{
+	int err = 0;
+	struct arm_smccc_res res;
+
+	if (sdei_firmware_call) {
+		sdei_firmware_call(function_id, arg0, arg1, arg2, arg3, arg4,
+				   &res);
+		if (sdei_is_err(&res))
+			err = sdei_to_linux_errno(res.a0);
+	} else {
+		/*
+		 * !sdei_firmware_call means we failed to probe or called
+		 * sdei_mark_interface_broken(). -EIO is not an error returned
+		 * by sdei_to_linux_errno() and is used to suppress messages
+		 * from this driver.
+		 */
+		err = -EIO;
+		res.a0 = SDEI_NOT_SUPPORTED;
+	}
+
+	if (result)
+		*result = res.a0;
+
+	return err;
+}
+
+static struct sdei_event *sdei_event_find(u32 event_num)
+{
+	struct sdei_event *e, *found = NULL;
+
+	lockdep_assert_held(&sdei_events_lock);
+
+	spin_lock(&sdei_list_lock);
+	list_for_each_entry(e, &sdei_list, list) {
+		if (e->event_num == event_num) {
+			found = e;
+			break;
+		}
+	}
+	spin_unlock(&sdei_list_lock);
+
+	return found;
+}
+
+int sdei_api_event_context(u32 query, u64 *result)
+{
+	return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_CONTEXT, query, 0, 0, 0, 0,
+			      result);
+}
+NOKPROBE_SYMBOL(sdei_api_event_context);
+
+static int sdei_api_event_get_info(u32 event, u32 info, u64 *result)
+{
+	return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_GET_INFO, event, info, 0,
+			      0, 0, result);
+}
+
+static struct sdei_event *sdei_event_create(u32 event_num,
+					    sdei_event_callback *cb,
+					    void *cb_arg)
+{
+	int err;
+	u64 result;
+	struct sdei_event *event;
+	struct sdei_registered_event *reg;
+
+	lockdep_assert_held(&sdei_events_lock);
+
+	event = kzalloc(sizeof(*event), GFP_KERNEL);
+	if (!event)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&event->list);
+	event->event_num = event_num;
+
+	err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_PRIORITY,
+				      &result);
+	if (err) {
+		kfree(event);
+		return ERR_PTR(err);
+	}
+	event->priority = result;
+
+	err = sdei_api_event_get_info(event_num, SDEI_EVENT_INFO_EV_TYPE,
+				      &result);
+	if (err) {
+		kfree(event);
+		return ERR_PTR(err);
+	}
+	event->type = result;
+
+	if (event->type == SDEI_EVENT_TYPE_SHARED) {
+		reg = kzalloc(sizeof(*reg), GFP_KERNEL);
+		if (!reg) {
+			kfree(event);
+			return ERR_PTR(-ENOMEM);
+		}
+
+		reg->event_num = event_num;
+		reg->priority = event->priority;
+
+		reg->callback = cb;
+		reg->callback_arg = cb_arg;
+		event->registered = reg;
+	}
+
+	if (sdei_event_find(event_num)) {
+		kfree(event->registered);
+		kfree(event);
+		event = ERR_PTR(-EBUSY);
+	} else {
+		spin_lock(&sdei_list_lock);
+		list_add(&event->list, &sdei_list);
+		spin_unlock(&sdei_list_lock);
+	}
+
+	return event;
+}
+
+static void sdei_event_destroy(struct sdei_event *event)
+{
+	lockdep_assert_held(&sdei_events_lock);
+
+	spin_lock(&sdei_list_lock);
+	list_del(&event->list);
+	spin_unlock(&sdei_list_lock);
+
+	if (event->type == SDEI_EVENT_TYPE_SHARED)
+		kfree(event->registered);
+
+	kfree(event);
+}
+
+static int sdei_api_get_version(u64 *version)
+{
+	return invoke_sdei_fn(SDEI_1_0_FN_SDEI_VERSION, 0, 0, 0, 0, 0, version);
+}
+
+int sdei_mask_local_cpu(void)
+{
+	int err;
+
+	WARN_ON_ONCE(preemptible());
+
+	err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_MASK, 0, 0, 0, 0, 0, NULL);
+	if (err && err != -EIO) {
+		pr_warn_once("failed to mask CPU[%u]: %d\n",
+			      smp_processor_id(), err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void _ipi_mask_cpu(void *ignored)
+{
+	sdei_mask_local_cpu();
+}
+
+int sdei_unmask_local_cpu(void)
+{
+	int err;
+
+	WARN_ON_ONCE(preemptible());
+
+	err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PE_UNMASK, 0, 0, 0, 0, 0, NULL);
+	if (err && err != -EIO) {
+		pr_warn_once("failed to unmask CPU[%u]: %d\n",
+			     smp_processor_id(), err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void _ipi_unmask_cpu(void *ignored)
+{
+	sdei_unmask_local_cpu();
+}
+
+static void _ipi_private_reset(void *ignored)
+{
+	int err;
+
+	err = invoke_sdei_fn(SDEI_1_0_FN_SDEI_PRIVATE_RESET, 0, 0, 0, 0, 0,
+			     NULL);
+	if (err && err != -EIO)
+		pr_warn_once("failed to reset CPU[%u]: %d\n",
+			     smp_processor_id(), err);
+}
+
+static int sdei_api_shared_reset(void)
+{
+	return invoke_sdei_fn(SDEI_1_0_FN_SDEI_SHARED_RESET, 0, 0, 0, 0, 0,
+			      NULL);
+}
+
+static void sdei_mark_interface_broken(void)
+{
+	pr_err("disabling SDEI firmware interface\n");
+	on_each_cpu(&_ipi_mask_cpu, NULL, true);
+	sdei_firmware_call = NULL;
+}
+
+static int sdei_platform_reset(void)
+{
+	int err;
+
+	on_each_cpu(&_ipi_private_reset, NULL, true);
+	err = sdei_api_shared_reset();
+	if (err) {
+		pr_err("Failed to reset platform: %d\n", err);
+		sdei_mark_interface_broken();
+	}
+
+	return err;
+}
+
+static int sdei_api_event_enable(u32 event_num)
+{
+	return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_ENABLE, event_num, 0, 0, 0,
+			      0, NULL);
+}
+
+int sdei_event_enable(u32 event_num)
+{
+	int err = -EINVAL;
+	struct sdei_event *event;
+
+	mutex_lock(&sdei_events_lock);
+	event = sdei_event_find(event_num);
+	if (!event) {
+		mutex_unlock(&sdei_events_lock);
+		return -ENOENT;
+	}
+
+	if (event->type == SDEI_EVENT_TYPE_SHARED)
+		err = sdei_api_event_enable(event->event_num);
+	mutex_unlock(&sdei_events_lock);
+
+	return err;
+}
+EXPORT_SYMBOL(sdei_event_enable);
+
+static int sdei_api_event_disable(u32 event_num)
+{
+	return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_DISABLE, event_num, 0, 0,
+			      0, 0, NULL);
+}
+
+int sdei_event_disable(u32 event_num)
+{
+	int err = -EINVAL;
+	struct sdei_event *event;
+
+	mutex_lock(&sdei_events_lock);
+	event = sdei_event_find(event_num);
+	if (!event) {
+		mutex_unlock(&sdei_events_lock);
+		return -ENOENT;
+	}
+
+	if (event->type == SDEI_EVENT_TYPE_SHARED)
+		err = sdei_api_event_disable(event->event_num);
+	mutex_unlock(&sdei_events_lock);
+
+	return err;
+}
+EXPORT_SYMBOL(sdei_event_disable);
+
+static int sdei_api_event_unregister(u32 event_num)
+{
+	return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_UNREGISTER, event_num, 0,
+			      0, 0, 0, NULL);
+}
+
+static int _sdei_event_unregister(struct sdei_event *event)
+{
+	lockdep_assert_held(&sdei_events_lock);
+
+	if (event->type == SDEI_EVENT_TYPE_SHARED)
+		return sdei_api_event_unregister(event->event_num);
+
+	return -EINVAL;
+}
+
+int sdei_event_unregister(u32 event_num)
+{
+	int err;
+	struct sdei_event *event;
+
+	WARN_ON(in_nmi());
+
+	mutex_lock(&sdei_events_lock);
+	event = sdei_event_find(event_num);
+	do {
+		if (!event) {
+			pr_warn("Event %u not registered\n", event_num);
+			err = -ENOENT;
+			break;
+		}
+
+		err = _sdei_event_unregister(event);
+		if (err)
+			break;
+
+		sdei_event_destroy(event);
+	} while (0);
+	mutex_unlock(&sdei_events_lock);
+
+	return err;
+}
+EXPORT_SYMBOL(sdei_event_unregister);
+
+static int sdei_api_event_register(u32 event_num, unsigned long entry_point,
+				   void *arg, u64 flags, u64 affinity)
+{
+	return invoke_sdei_fn(SDEI_1_0_FN_SDEI_EVENT_REGISTER, event_num,
+			      (unsigned long)entry_point, (unsigned long)arg,
+			      flags, affinity, NULL);
+}
+
+static int _sdei_event_register(struct sdei_event *event)
+{
+	lockdep_assert_held(&sdei_events_lock);
+
+	if (event->type == SDEI_EVENT_TYPE_SHARED)
+		return sdei_api_event_register(event->event_num,
+					       sdei_entry_point,
+					       event->registered,
+					       SDEI_EVENT_REGISTER_RM_ANY, 0);
+
+	return -EINVAL;
+}
+
+int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg)
+{
+	int err;
+	struct sdei_event *event;
+
+	WARN_ON(in_nmi());
+
+	mutex_lock(&sdei_events_lock);
+	do {
+		if (sdei_event_find(event_num)) {
+			pr_warn("Event %u already registered\n", event_num);
+			err = -EBUSY;
+			break;
+		}
+
+		event = sdei_event_create(event_num, cb, arg);
+		if (IS_ERR(event)) {
+			err = PTR_ERR(event);
+			pr_warn("Failed to create event %u: %d\n", event_num,
+				err);
+			break;
+		}
+
+		err = _sdei_event_register(event);
+		if (err) {
+			sdei_event_destroy(event);
+			pr_warn("Failed to register event %u: %d\n", event_num,
+				err);
+		}
+	} while (0);
+	mutex_unlock(&sdei_events_lock);
+
+	return err;
+}
+EXPORT_SYMBOL(sdei_event_register);
+
+static void sdei_smccc_smc(unsigned long function_id,
+			   unsigned long arg0, unsigned long arg1,
+			   unsigned long arg2, unsigned long arg3,
+			   unsigned long arg4, struct arm_smccc_res *res)
+{
+	arm_smccc_smc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res);
+}
+
+static void sdei_smccc_hvc(unsigned long function_id,
+			   unsigned long arg0, unsigned long arg1,
+			   unsigned long arg2, unsigned long arg3,
+			   unsigned long arg4, struct arm_smccc_res *res)
+{
+	arm_smccc_hvc(function_id, arg0, arg1, arg2, arg3, arg4, 0, 0, res);
+}
+
+static int sdei_get_conduit(struct platform_device *pdev)
+{
+	const char *method;
+	struct device_node *np = pdev->dev.of_node;
+
+	sdei_firmware_call = NULL;
+	if (np) {
+		if (of_property_read_string(np, "method", &method)) {
+			pr_warn("missing \"method\" property\n");
+			return CONDUIT_INVALID;
+		}
+
+		if (!strcmp("hvc", method)) {
+			sdei_firmware_call = &sdei_smccc_hvc;
+			return CONDUIT_HVC;
+		} else if (!strcmp("smc", method)) {
+			sdei_firmware_call = &sdei_smccc_smc;
+			return CONDUIT_SMC;
+		}
+
+		pr_warn("invalid \"method\" property: %s\n", method);
+	}
+
+	return CONDUIT_INVALID;
+}
+
+static int sdei_probe(struct platform_device *pdev)
+{
+	int err;
+	u64 ver = 0;
+	int conduit;
+
+	conduit = sdei_get_conduit(pdev);
+	if (!sdei_firmware_call)
+		return 0;
+
+	err = sdei_api_get_version(&ver);
+	if (err == -EOPNOTSUPP)
+		pr_err("advertised but not implemented in platform firmware\n");
+	if (err) {
+		pr_err("Failed to get SDEI version: %d\n", err);
+		sdei_mark_interface_broken();
+		return err;
+	}
+
+	pr_info("SDEIv%d.%d (0x%x) detected in firmware.\n",
+		(int)SDEI_VERSION_MAJOR(ver), (int)SDEI_VERSION_MINOR(ver),
+		(int)SDEI_VERSION_VENDOR(ver));
+
+	if (SDEI_VERSION_MAJOR(ver) != 1) {
+		pr_warn("Conflicting SDEI version detected.\n");
+		sdei_mark_interface_broken();
+		return -EINVAL;
+	}
+
+	err = sdei_platform_reset();
+	if (err)
+		return err;
+
+	sdei_entry_point = sdei_arch_get_entry_point(conduit);
+	if (!sdei_entry_point) {
+		/* Not supported due to hardware or boot configuration */
+		sdei_mark_interface_broken();
+		return 0;
+	}
+
+	on_each_cpu(&_ipi_unmask_cpu, NULL, false);
+
+	return 0;
+}
+
+static const struct of_device_id sdei_of_match[] = {
+	{ .compatible = "arm,sdei-1.0" },
+	{}
+};
+
+static struct platform_driver sdei_driver = {
+	.driver		= {
+		.name			= "sdei",
+		.of_match_table		= sdei_of_match,
+	},
+	.probe		= sdei_probe,
+};
+
+static bool __init sdei_present_dt(void)
+{
+	struct platform_device *pdev;
+	struct device_node *np, *fw_np;
+
+	fw_np = of_find_node_by_name(NULL, "firmware");
+	if (!fw_np)
+		return false;
+
+	np = of_find_matching_node(fw_np, sdei_of_match);
+	of_node_put(fw_np);
+	if (!np)
+		return false;
+
+	pdev = of_platform_device_create(np, sdei_driver.driver.name, NULL);
+	of_node_put(np);
+	if (IS_ERR(pdev))
+		return false;
+
+	return true;
+}
+
+static int __init sdei_init(void)
+{
+	if (sdei_present_dt())
+		platform_driver_register(&sdei_driver);
+
+	return 0;
+}
+
+subsys_initcall_sync(sdei_init);
+
+int sdei_event_handler(struct pt_regs *regs,
+		       struct sdei_registered_event *arg)
+{
+	int err;
+	mm_segment_t orig_addr_limit;
+	u32 event_num = arg->event_num;
+
+	orig_addr_limit = get_fs();
+	set_fs(USER_DS);
+
+	err = arg->callback(event_num, regs, arg->callback_arg);
+	if (err)
+		pr_err_ratelimited("event %u on CPU %u failed with error: %d\n",
+				   event_num, smp_processor_id(), err);
+
+	set_fs(orig_addr_limit);
+
+	return err;
+}
+NOKPROBE_SYMBOL(sdei_event_handler);
diff --git a/include/linux/arm_sdei.h b/include/linux/arm_sdei.h
new file mode 100644
index 000000000000..942afbd544b7
--- /dev/null
+++ b/include/linux/arm_sdei.h
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2017 Arm Ltd.
+#ifndef __LINUX_ARM_SDEI_H
+#define __LINUX_ARM_SDEI_H
+
+#include <uapi/linux/arm_sdei.h>
+
+enum sdei_conduit_types {
+	CONDUIT_INVALID = 0,
+	CONDUIT_SMC,
+	CONDUIT_HVC,
+};
+
+#include <asm/sdei.h>
+
+/* Arch code should override this to set the entry point from firmware... */
+#ifndef sdei_arch_get_entry_point
+#define sdei_arch_get_entry_point(conduit)	(0)
+#endif
+
+/*
+ * When an event occurs sdei_event_handler() will call a user-provided callback
+ * like this in NMI context on the CPU that received the event.
+ */
+typedef int (sdei_event_callback)(u32 event, struct pt_regs *regs, void *arg);
+
+/*
+ * Register your callback to claim an event. The event must be described
+ * by firmware.
+ */
+int sdei_event_register(u32 event_num, sdei_event_callback *cb, void *arg);
+
+/*
+ * Calls to sdei_event_unregister() may return EINPROGRESS. Keep calling
+ * it until it succeeds.
+ */
+int sdei_event_unregister(u32 event_num);
+
+int sdei_event_enable(u32 event_num);
+int sdei_event_disable(u32 event_num);
+
+#ifdef CONFIG_ARM_SDE_INTERFACE
+/* For use by arch code when CPU hotplug notifiers are not appropriate. */
+int sdei_mask_local_cpu(void);
+int sdei_unmask_local_cpu(void);
+#else
+static inline int sdei_mask_local_cpu(void) { return 0; }
+static inline int sdei_unmask_local_cpu(void) { return 0; }
+#endif /* CONFIG_ARM_SDE_INTERFACE */
+
+
+/*
+ * This struct represents an event that has been registered. The driver
+ * maintains a list of all events, and which ones are registered. (Private
+ * events have one entry in the list, but are registered on each CPU).
+ * A pointer to this struct is passed to firmware, and back to the event
+ * handler. The event handler can then use this to invoke the registered
+ * callback, without having to walk the list.
+ *
+ * For CPU private events, this structure is per-cpu.
+ */
+struct sdei_registered_event {
+	/* For use by arch code: */
+	struct pt_regs          interrupted_regs;
+
+	sdei_event_callback	*callback;
+	void			*callback_arg;
+	u32			 event_num;
+	u8			 priority;
+};
+
+/* The arch code entry point should then call this when an event arrives. */
+int notrace sdei_event_handler(struct pt_regs *regs,
+			       struct sdei_registered_event *arg);
+
+/* arch code may use this to retrieve the extra registers. */
+int sdei_api_event_context(u32 query, u64 *result);
+
+#endif /* __LINUX_ARM_SDEI_H */
diff --git a/include/uapi/linux/arm_sdei.h b/include/uapi/linux/arm_sdei.h
new file mode 100644
index 000000000000..af0630ba5437
--- /dev/null
+++ b/include/uapi/linux/arm_sdei.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* Copyright (C) 2017 Arm Ltd. */
+#ifndef _UAPI_LINUX_ARM_SDEI_H
+#define _UAPI_LINUX_ARM_SDEI_H
+
+#define SDEI_1_0_FN_BASE			0xC4000020
+#define SDEI_1_0_MASK				0xFFFFFFE0
+#define SDEI_1_0_FN(n)				(SDEI_1_0_FN_BASE + (n))
+
+#define SDEI_1_0_FN_SDEI_VERSION			SDEI_1_0_FN(0x00)
+#define SDEI_1_0_FN_SDEI_EVENT_REGISTER			SDEI_1_0_FN(0x01)
+#define SDEI_1_0_FN_SDEI_EVENT_ENABLE			SDEI_1_0_FN(0x02)
+#define SDEI_1_0_FN_SDEI_EVENT_DISABLE			SDEI_1_0_FN(0x03)
+#define SDEI_1_0_FN_SDEI_EVENT_CONTEXT			SDEI_1_0_FN(0x04)
+#define SDEI_1_0_FN_SDEI_EVENT_COMPLETE			SDEI_1_0_FN(0x05)
+#define SDEI_1_0_FN_SDEI_EVENT_COMPLETE_AND_RESUME	SDEI_1_0_FN(0x06)
+#define SDEI_1_0_FN_SDEI_EVENT_UNREGISTER		SDEI_1_0_FN(0x07)
+#define SDEI_1_0_FN_SDEI_EVENT_STATUS			SDEI_1_0_FN(0x08)
+#define SDEI_1_0_FN_SDEI_EVENT_GET_INFO			SDEI_1_0_FN(0x09)
+#define SDEI_1_0_FN_SDEI_EVENT_ROUTING_SET		SDEI_1_0_FN(0x0A)
+#define SDEI_1_0_FN_SDEI_PE_MASK			SDEI_1_0_FN(0x0B)
+#define SDEI_1_0_FN_SDEI_PE_UNMASK			SDEI_1_0_FN(0x0C)
+#define SDEI_1_0_FN_SDEI_INTERRUPT_BIND			SDEI_1_0_FN(0x0D)
+#define SDEI_1_0_FN_SDEI_INTERRUPT_RELEASE		SDEI_1_0_FN(0x0E)
+#define SDEI_1_0_FN_SDEI_PRIVATE_RESET			SDEI_1_0_FN(0x11)
+#define SDEI_1_0_FN_SDEI_SHARED_RESET			SDEI_1_0_FN(0x12)
+
+#define SDEI_VERSION_MAJOR_SHIFT			48
+#define SDEI_VERSION_MAJOR_MASK				0x7fff
+#define SDEI_VERSION_MINOR_SHIFT			32
+#define SDEI_VERSION_MINOR_MASK				0xffff
+#define SDEI_VERSION_VENDOR_SHIFT			0
+#define SDEI_VERSION_VENDOR_MASK			0xffffffff
+
+#define SDEI_VERSION_MAJOR(x)	(x>>SDEI_VERSION_MAJOR_SHIFT & SDEI_VERSION_MAJOR_MASK)
+#define SDEI_VERSION_MINOR(x)	(x>>SDEI_VERSION_MINOR_SHIFT & SDEI_VERSION_MINOR_MASK)
+#define SDEI_VERSION_VENDOR(x)	(x>>SDEI_VERSION_VENDOR_SHIFT & SDEI_VERSION_VENDOR_MASK)
+
+/* SDEI return values */
+#define SDEI_SUCCESS		0
+#define SDEI_NOT_SUPPORTED	-1
+#define SDEI_INVALID_PARAMETERS	-2
+#define SDEI_DENIED		-3
+#define SDEI_PENDING		-5
+#define SDEI_OUT_OF_RESOURCE	-10
+
+/* EVENT_REGISTER flags */
+#define SDEI_EVENT_REGISTER_RM_ANY	0
+#define SDEI_EVENT_REGISTER_RM_PE	1
+
+/* EVENT_STATUS return value bits */
+#define SDEI_EVENT_STATUS_RUNNING	2
+#define SDEI_EVENT_STATUS_ENABLED	1
+#define SDEI_EVENT_STATUS_REGISTERED	0
+
+/* EVENT_COMPLETE status values */
+#define SDEI_EV_HANDLED	0
+#define SDEI_EV_FAILED	1
+
+/* GET_INFO values */
+#define SDEI_EVENT_INFO_EV_TYPE			0
+#define SDEI_EVENT_INFO_EV_SIGNALED		1
+#define SDEI_EVENT_INFO_EV_PRIORITY		2
+#define SDEI_EVENT_INFO_EV_ROUTING_MODE		3
+#define SDEI_EVENT_INFO_EV_ROUTING_AFF		4
+
+/* and their results */
+#define SDEI_EVENT_TYPE_PRIVATE			0
+#define SDEI_EVENT_TYPE_SHARED			1
+#define SDEI_EVENT_PRIORITY_NORMAL		0
+#define SDEI_EVENT_PRIORITY_CRITICAL		1
+
+#endif /* _UAPI_LINUX_ARM_SDEI_H */
-- 
2.15.0

^ permalink raw reply related

* [PATCH v6 08/16] arm64: Add vmap_stack header file
From: James Morse @ 2018-01-08 15:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108153818.22743-1-james.morse@arm.com>

Today the arm64 arch code allocates an extra IRQ stack per-cpu. If we
also have SDEI and VMAP stacks we need two extra per-cpu VMAP stacks.

Move the VMAP stack allocation out to a helper in a new header file.
This avoids missing THREADINFO_GFP, or getting the all-important alignment
wrong.

Signed-off-by: James Morse <james.morse@arm.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Mark Rutland <mark.rutland@arm.com>
---
Changes since v5:
 * Added two required header files

Changes since v4:
 * Added gfp.h include

Changes since v3:
 * Added BUILD_BUG() instead of a spooky link error

 arch/arm64/include/asm/vmap_stack.h | 28 ++++++++++++++++++++++++++++
 arch/arm64/kernel/irq.c             | 13 ++-----------
 2 files changed, 30 insertions(+), 11 deletions(-)
 create mode 100644 arch/arm64/include/asm/vmap_stack.h

diff --git a/arch/arm64/include/asm/vmap_stack.h b/arch/arm64/include/asm/vmap_stack.h
new file mode 100644
index 000000000000..0b5ec6e08c10
--- /dev/null
+++ b/arch/arm64/include/asm/vmap_stack.h
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2017 Arm Ltd.
+#ifndef __ASM_VMAP_STACK_H
+#define __ASM_VMAP_STACK_H
+
+#include <linux/bug.h>
+#include <linux/gfp.h>
+#include <linux/kconfig.h>
+#include <linux/vmalloc.h>
+#include <asm/memory.h>
+#include <asm/pgtable.h>
+#include <asm/thread_info.h>
+
+/*
+ * To ensure that VMAP'd stack overflow detection works correctly, all VMAP'd
+ * stacks need to have the same alignment.
+ */
+static inline unsigned long *arch_alloc_vmap_stack(size_t stack_size, int node)
+{
+	BUILD_BUG_ON(!IS_ENABLED(CONFIG_VMAP_STACK));
+
+	return __vmalloc_node_range(stack_size, THREAD_ALIGN,
+				    VMALLOC_START, VMALLOC_END,
+				    THREADINFO_GFP, PAGE_KERNEL, 0, node,
+				    __builtin_return_address(0));
+}
+
+#endif /* __ASM_VMAP_STACK_H */
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c
index 713561e5bcab..60e5fc661f74 100644
--- a/arch/arm64/kernel/irq.c
+++ b/arch/arm64/kernel/irq.c
@@ -29,6 +29,7 @@
 #include <linux/irqchip.h>
 #include <linux/seq_file.h>
 #include <linux/vmalloc.h>
+#include <asm/vmap_stack.h>
 
 unsigned long irq_err_count;
 
@@ -58,17 +59,7 @@ static void init_irq_stacks(void)
 	unsigned long *p;
 
 	for_each_possible_cpu(cpu) {
-		/*
-		* To ensure that VMAP'd stack overflow detection works
-		* correctly, the IRQ stacks need to have the same
-		* alignment as other stacks.
-		*/
-		p = __vmalloc_node_range(IRQ_STACK_SIZE, THREAD_ALIGN,
-					 VMALLOC_START, VMALLOC_END,
-					 THREADINFO_GFP, PAGE_KERNEL,
-					 0, cpu_to_node(cpu),
-					 __builtin_return_address(0));
-
+		p = arch_alloc_vmap_stack(IRQ_STACK_SIZE, cpu_to_node(cpu));
 		per_cpu(irq_stack_ptr, cpu) = p;
 	}
 }
-- 
2.15.0

^ permalink raw reply related

* [PATCH v6 09/16] arm64: uaccess: Add PAN helper
From: James Morse @ 2018-01-08 15:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180108153818.22743-1-james.morse@arm.com>

Add __uaccess_{en,dis}able_hw_pan() helpers to set/clear the PSTATE.PAN
bit.

Signed-off-by: James Morse <james.morse@arm.com>
---
 arch/arm64/include/asm/uaccess.h | 12 ++++++++++++
 arch/arm64/kernel/suspend.c      |  4 ++--
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h
index 6eadf55ebaf0..3821fab01d7d 100644
--- a/arch/arm64/include/asm/uaccess.h
+++ b/arch/arm64/include/asm/uaccess.h
@@ -168,6 +168,18 @@ static inline bool uaccess_ttbr0_enable(void)
 }
 #endif
 
+static inline void __uaccess_disable_hw_pan(void)
+{
+	asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN,
+			CONFIG_ARM64_PAN));
+}
+
+static inline void __uaccess_enable_hw_pan(void)
+{
+	asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,
+			CONFIG_ARM64_PAN));
+}
+
 #define __uaccess_disable(alt)						\
 do {									\
 	if (!uaccess_ttbr0_disable())					\
diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c
index 3fe5ad884418..a307b9e13392 100644
--- a/arch/arm64/kernel/suspend.c
+++ b/arch/arm64/kernel/suspend.c
@@ -2,6 +2,7 @@
 #include <linux/ftrace.h>
 #include <linux/percpu.h>
 #include <linux/slab.h>
+#include <linux/uaccess.h>
 #include <asm/alternative.h>
 #include <asm/cacheflush.h>
 #include <asm/cpufeature.h>
@@ -51,8 +52,7 @@ void notrace __cpu_suspend_exit(void)
 	 * PSTATE was not saved over suspend/resume, re-enable any detected
 	 * features that might not have been set correctly.
 	 */
-	asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,
-			CONFIG_ARM64_PAN));
+	__uaccess_enable_hw_pan();
 	uao_thread_switch(current);
 
 	/*
-- 
2.15.0

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox