* Re: [PATCH v4 1/2] ACPI/PPTT: Add support for ACPI 6.3 thread flag
From: Jeremy Linton @ 2019-08-02 15:36 UTC (permalink / raw)
To: Robert Richter
Cc: lorenzo.pieralisi, catalin.marinas, rjw, linux-acpi, sudeep.holla,
will, linux-arm-kernel, lenb
In-Reply-To: <20190802130510.rd4uyndtqlcfdhtm@rric.localdomain>
Hi,
Thanks for taking a look at this.
On 8/2/19 8:05 AM, Robert Richter wrote:
> On 31.07.19 22:46:33, Jeremy Linton wrote:
>
>> diff --git a/include/linux/acpi.h b/include/linux/acpi.h
>> index 9426b9aaed86..9d0e20a2ac83 100644
>> --- a/include/linux/acpi.h
>> +++ b/include/linux/acpi.h
>> @@ -1302,11 +1302,16 @@ static inline int lpit_read_residency_count_address(u64 *address)
>> #endif
>>
>> #ifdef CONFIG_ACPI_PPTT
>> +int acpi_pptt_cpu_is_thread(unsigned int cpu);
>> int find_acpi_cpu_topology(unsigned int cpu, int level);
>> int find_acpi_cpu_topology_package(unsigned int cpu);
>> int find_acpi_cpu_topology_hetero_id(unsigned int cpu);
>> int find_acpi_cpu_cache_topology(unsigned int cpu, int level);
>
> All those functions (exept hetero_id) are used only in
> parse_acpi_topology(). So how about creating a struct with thread_id,
> core_id, and cache_id (and hetero_id (?)) and have a single pptt table
> parsing function that fills in all of this into that struct? This
> simplifies the api and also the code.
>
> This also shows that hetid (see arm_pmu_acpi.c) better should be
> stored in cpu_topology[] too and thus being parsed with the other
> parameters as well and made accessible from there by a helper.
I think the idea here was to avoid an additional set of intermediate
data structures between the PPTT table/structure and the final arch
specific data structures (which themselves are used to feed other
things, like the scheduler, note the llc parsing). Rather the attempt is
to provide a set of tools to retrieve information and let the policy for
how that information is used be dictated by the consumer.
In the future, if we can further unify the arch specific cpu_topology
structures it would make sense to parse directly into them, but until
that happens I don't think we should try. The existing code does parse
directly into the cache structures, but the cpu topology is subtly arm64
at the moment. If another arch decided to use this, i'm not sure they
would want or need it parsed in exactly the same way.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: kvm-unit-tests: psci_cpu_on_test FAILed
From: Marc Zyngier @ 2019-08-02 15:56 UTC (permalink / raw)
To: Zenghui Yu, drjones, James Morse, julien.thierry.kdev,
suzuki.poulose
Cc: linux-arm-kernel, Wanghaibin (D), kvmarm, kvm
In-Reply-To: <3ddf8766-6f02-b655-1b80-d8a7fd016509@huawei.com>
On 02/08/2019 11:56, Zenghui Yu wrote:
> Hi folks,
>
> Running kvm-unit-tests with Linux 5.3.0-rc2 on Kunpeng 920, we will get
> the following fail info:
>
> [...]
> FAIL psci (4 tests, 1 unexpected failures)
> [...]
> and
> [...]
> INFO: unexpected cpu_on return value: caller=CPU9, ret=-2
> FAIL: cpu-on
> SUMMARY: 4 tests, 1 unexpected failures
>
>
> I think this is an issue had been fixed once by commit 6c7a5dce22b3
> ("KVM: arm/arm64: fix races in kvm_psci_vcpu_on"), which makes use of
> kvm->lock mutex to fix the race between two PSCI_CPU_ON calls - one
> does reset on the MPIDR register whilst another reads it.
>
> But commit 358b28f09f0 ("arm/arm64: KVM: Allow a VCPU to fully reset
> itself") later moves the reset work into check_vcpu_requests(), by
> making a KVM_REQ_VCPU_RESET request in PSCI code. Thus the reset work
> has not been protected by kvm->lock mutex anymore, and the race shows up
> again...
>
> Do we need a fix for this issue? At least achieve a mutex execution
> between the reset of MPIDR and kvm_mpidr_to_vcpu()?
The thing is that the way we reset registers is marginally insane.
Yes, it catches most reset bugs. It also introduces many more in
the rest of the paths.
The fun part is that there is hardly a need for resetting MPIDR.
It has already been set when we've created the vcpu. It is the
poisoning of the sysreg array that creates a situation where
the MPIDR is temporarily invalid.
So instead of poisoning the array, how about we just keep
track of the registers for which we've called a reset function?
It should be enough to track the most obvious bugs... I've
cobbled the following patch together, which seems to fix the
issue on my TX2 with 64 vcpus.
Thoughts?
M.
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index f26e181d881c..17f46ee7dc83 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2254,13 +2254,17 @@ static int emulate_sys_reg(struct kvm_vcpu *vcpu,
}
static void reset_sys_reg_descs(struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *table, size_t num)
+ const struct sys_reg_desc *table, size_t num,
+ unsigned long *bmap)
{
unsigned long i;
for (i = 0; i < num; i++)
- if (table[i].reset)
+ if (table[i].reset) {
table[i].reset(vcpu, &table[i]);
+ if (bmap)
+ set_bit(i, bmap);
+ }
}
/**
@@ -2772,21 +2776,23 @@ void kvm_sys_reg_table_init(void)
*/
void kvm_reset_sys_regs(struct kvm_vcpu *vcpu)
{
+ unsigned long *bmap;
size_t num;
const struct sys_reg_desc *table;
- /* Catch someone adding a register without putting in reset entry. */
- memset(&vcpu->arch.ctxt.sys_regs, 0x42, sizeof(vcpu->arch.ctxt.sys_regs));
+ bmap = bitmap_alloc(NR_SYS_REGS, GFP_KERNEL);
/* Generic chip reset first (so target could override). */
- reset_sys_reg_descs(vcpu, sys_reg_descs, ARRAY_SIZE(sys_reg_descs));
+ reset_sys_reg_descs(vcpu, sys_reg_descs, ARRAY_SIZE(sys_reg_descs), bmap);
table = get_target_table(vcpu->arch.target, true, &num);
- reset_sys_reg_descs(vcpu, table, num);
+ reset_sys_reg_descs(vcpu, table, num, bmap);
for (num = 1; num < NR_SYS_REGS; num++) {
- if (WARN(__vcpu_sys_reg(vcpu, num) == 0x4242424242424242,
+ if (WARN(bmap && !test_bit(num, bmap),
"Didn't reset __vcpu_sys_reg(%zi)\n", num))
break;
}
+
+ kfree(bmap);
}
--
Jazz is not dead, it just smells funny...
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH v4 2/2] arm64: topology: Use PPTT to determine if PE is a thread
From: Jeremy Linton @ 2019-08-02 16:04 UTC (permalink / raw)
To: Robert Richter
Cc: lorenzo.pieralisi, catalin.marinas, rjw, linux-acpi, sudeep.holla,
will, linux-arm-kernel, lenb
In-Reply-To: <20190802134427.dmclik66zcgxapy3@rric.localdomain>
Hi,
On 8/2/19 8:44 AM, Robert Richter wrote:
> On 31.07.19 22:46:34, Jeremy Linton wrote:
>
>> @@ -358,6 +356,10 @@ static int __init parse_acpi_topology(void)
>> if (topology_id < 0)
>> return topology_id;
>>
>> + is_threaded = acpi_pptt_cpu_is_thread(cpu);
>> + if (is_threaded < 0)
>> + is_threaded = read_cpuid_mpidr() & MPIDR_MT_BITMASK;
>> +
>
> I think the return code handling is error-prone, as in the kernel such
> functions are typically used like:
>
> if (something_is_thread) { ... }
I don't really understand why this keeps getting repeated. The negative
error code return is used by huge swaths of the kernel API. A couple
lines up the exact same paradigm is used in get_cpu_for_node() and a few
other places.
>
> I see this is due to acpi and arch code separation so we cannot simply
> move the fallback to pptt code.
Right, the PPTT->arch data structure translation is arch specific.
During the initial PPTT drop a lot of discussion when into how arm64 was
doing that translation, as well as the corresponding translation to the
core scheduler/etc.
>
> So maybe we have a static function cpu_is_thread() in this file that
> handles all the logic and directly use check_acpi_cpu_flag() from
> there. However, code may change here in case of a rework as I
> suggested in patch #1. In both cases the acpi api is more straight
> then.
I'm ok with that, it effectively only moves those three lines to a
standalone single call-site function. To be clear, that isn't a generic
routine for anyone to call. Functions that need to know if the core is a
threaded should be checking the topology thread_id directly rather than
re-coding the acpi/dt/mpidr logic which populates it.
>
> -Robert
>
>> if (is_threaded) {
>> cpu_topology[cpu].thread_id = topology_id;
>> topology_id = find_acpi_cpu_topology(cpu, 1);
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [GIT PULL] arm highmem block I/O regression fix for 5.3
From: pr-tracker-bot @ 2019-08-02 16:05 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Vignesh Raghavendra, Konrad Rzeszutek Wilk, Russell King,
linux-kernel, iommu, linux-arm-kernel, Linus Torvalds,
Nicolas Saenz Julienne, Roger Quadros
In-Reply-To: <20190801164702.GA26365@infradead.org>
The pull request you sent on Thu, 1 Aug 2019 19:47:02 +0300:
> git://git.infradead.org/users/hch/dma-mapping.git tags/arm-swiotlb-5.3
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/234172f6bbf8e26fa8407c4bbbf2a36da30d7913
Thank you!
--
Deet-doot-dot, I am a bot.
https://korg.wiki.kernel.org/userdoc/prtracker
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v3] tracing: Function stack size and its name mismatch in arm64
From: Steven Rostedt @ 2019-08-02 16:09 UTC (permalink / raw)
To: Jiping Ma
Cc: catalin.marinas, will.deacon, linux-kernel, mingo, joel,
linux-arm-kernel
In-Reply-To: <20190802112259.0530a648@gandalf.local.home>
[-- Attachment #1: Type: text/plain, Size: 1556 bytes --]
On Fri, 2 Aug 2019 11:22:59 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:
> I think you are not explaining the issue correctly. From looking at the
> document, I think what you want to say is that the LR is saved *after*
> the data for the function. Is that correct? If so, then yes, it would
> cause the stack tracing algorithm to be incorrect.
>
[..]
> Can someone confirm that this is the real issue?
Does this patch fix your issue?
-- Steve
diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
index 5ab5200b2bdc..13a4832cfb00 100644
--- a/arch/arm64/include/asm/ftrace.h
+++ b/arch/arm64/include/asm/ftrace.h
@@ -13,6 +13,7 @@
#define HAVE_FUNCTION_GRAPH_FP_TEST
#define MCOUNT_ADDR ((unsigned long)_mcount)
#define MCOUNT_INSN_SIZE AARCH64_INSN_SIZE
+#define ARCH_RET_ADDR_AFTER_LOCAL_VARS 1
#ifndef __ASSEMBLY__
#include <linux/compat.h>
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index 5d16f73898db..050c6bd9beac 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -158,6 +158,18 @@ static void check_stack(unsigned long ip, unsigned long *stack)
i++;
}
+#ifdef ARCH_RET_ADDR_AFTER_LOCAL_VARS
+ /*
+ * Most archs store the return address before storing the
+ * function's local variables. But some archs do this backwards.
+ */
+ if (x > 1) {
+ memmove(&stack_trace_index[0], &stack_trace_index[1],
+ sizeof(stack_trace_index[0]) * (x - 1));
+ x--;
+ }
+#endif
+
stack_trace_nr_entries = x;
if (task_stack_end_corrupted(current)) {
[-- Attachment #2: f.patch --]
[-- Type: text/x-patch, Size: 1100 bytes --]
diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
index 5ab5200b2bdc..13a4832cfb00 100644
--- a/arch/arm64/include/asm/ftrace.h
+++ b/arch/arm64/include/asm/ftrace.h
@@ -13,6 +13,7 @@
#define HAVE_FUNCTION_GRAPH_FP_TEST
#define MCOUNT_ADDR ((unsigned long)_mcount)
#define MCOUNT_INSN_SIZE AARCH64_INSN_SIZE
+#define ARCH_RET_ADDR_AFTER_LOCAL_VARS 1
#ifndef __ASSEMBLY__
#include <linux/compat.h>
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index 5d16f73898db..050c6bd9beac 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -158,6 +158,18 @@ static void check_stack(unsigned long ip, unsigned long *stack)
i++;
}
+#ifdef ARCH_RET_ADDR_AFTER_LOCAL_VARS
+ /*
+ * Most archs store the return address before storing the
+ * function's local variables. But some archs do this backwards.
+ */
+ if (x > 1) {
+ memmove(&stack_trace_index[0], &stack_trace_index[1],
+ sizeof(stack_trace_index[0]) * (x - 1));
+ x--;
+ }
+#endif
+
stack_trace_nr_entries = x;
if (task_stack_end_corrupted(current)) {
[-- Attachment #3: Type: text/plain, Size: 176 bytes --]
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* RE: [PATCH 20/34] xen: convert put_page() to put_user_page*()
From: Weiny, Ira @ 2019-08-02 16:09 UTC (permalink / raw)
To: Juergen Gross, John Hubbard, john.hubbard@gmail.com,
Andrew Morton
Cc: linux-fbdev@vger.kernel.org, Jan Kara, kvm@vger.kernel.org,
Boris Ostrovsky, Dave Hansen, Dave Chinner,
dri-devel@lists.freedesktop.org, linux-mm@kvack.org,
sparclinux@vger.kernel.org, Williams, Dan J,
devel@driverdev.osuosl.org, rds-devel@oss.oracle.com,
linux-rdma@vger.kernel.org, x86@kernel.org,
amd-gfx@lists.freedesktop.org, Christoph Hellwig, Jason Gunthorpe,
xen-devel@lists.xenproject.org, devel@lists.orangefs.org,
linux-media@vger.kernel.org, intel-gfx@lists.freedesktop.org,
linux-block@vger.kernel.org, Jérôme Glisse,
linux-rpi-kernel@lists.infradead.org, ceph-devel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, linux-nfs@vger.kernel.org,
netdev@vger.kernel.org, LKML, linux-xfs@vger.kernel.org,
linux-crypto@vger.kernel.org, linux-fsdevel@vger.kernel.org
In-Reply-To: <d4931311-db01-e8c3-0f8c-d64685dc2143@suse.com>
>
> On 02.08.19 07:48, John Hubbard wrote:
> > On 8/1/19 9:36 PM, Juergen Gross wrote:
> >> On 02.08.19 04:19, john.hubbard@gmail.com wrote:
> >>> From: John Hubbard <jhubbard@nvidia.com>
> > ...
> >>> diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index
> >>> 2f5ce7230a43..29e461dbee2d 100644
> >>> --- a/drivers/xen/privcmd.c
> >>> +++ b/drivers/xen/privcmd.c
> >>> @@ -611,15 +611,10 @@ static int lock_pages(
> >>> static void unlock_pages(struct page *pages[], unsigned int
> >>> nr_pages)
> >>> {
> >>> - unsigned int i;
> >>> -
> >>> if (!pages)
> >>> return;
> >>> - for (i = 0; i < nr_pages; i++) {
> >>> - if (pages[i])
> >>> - put_page(pages[i]);
> >>> - }
> >>> + put_user_pages(pages, nr_pages);
> >>
> >> You are not handling the case where pages[i] is NULL here. Or am I
> >> missing a pending patch to put_user_pages() here?
> >>
> >
> > Hi Juergen,
> >
> > You are correct--this no longer handles the cases where pages[i] is
> > NULL. It's intentional, though possibly wrong. :)
> >
> > I see that I should have added my standard blurb to this commit
> > description. I missed this one, but some of the other patches have it.
> > It makes the following, possibly incorrect claim:
> >
> > "This changes the release code slightly, because each page slot in the
> > page_list[] array is no longer checked for NULL. However, that check
> > was wrong anyway, because the get_user_pages() pattern of usage here
> > never allowed for NULL entries within a range of pinned pages."
> >
> > The way I've seen these page arrays used with get_user_pages(), things
> > are either done single page, or with a contiguous range. So unless I'm
> > missing a case where someone is either
> >
> > a) releasing individual pages within a range (and thus likely messing
> > up their count of pages they have), or
> >
> > b) allocating two gup ranges within the same pages[] array, with a gap
> > between the allocations,
> >
> > ...then it should be correct. If so, then I'll add the above blurb to
> > this patch's commit description.
> >
> > If that's not the case (both here, and in 3 or 4 other patches in this
> > series, then as you said, I should add NULL checks to put_user_pages()
> > and put_user_pages_dirty_lock().
>
> In this case it is not correct, but can easily be handled. The NULL case can
> occur only in an error case with the pages array filled partially or not at all.
>
> I'd prefer something like the attached patch here.
I'm not an expert in this code and have not looked at it carefully but that patch does seem to be the better fix than forcing NULL checks on everyone.
Ira
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH -next 09/12] crypto: rockchip - use devm_platform_ioremap_resource() to simplify code
From: Heiko Stuebner @ 2019-08-02 16:09 UTC (permalink / raw)
To: YueHaibing
Cc: gary.hook, clabbe.montjoie, linux-arm-kernel, jamie, linux-stm32,
jesper.nilsson, linux-samsung-soc, herbert, krzk, linux-rockchip,
wens, agross, thomas.lendacky, alexandre.torgue, antoine.tenart,
linux-arm-msm, mripard, linux-mediatek, lars.persson,
matthias.bgg, linux-arm-kernel, linux-kernel, linux-crypto,
mcoquelin.stm32, kgene, davem
In-Reply-To: <20190802132809.8116-10-yuehaibing@huawei.com>
Am Freitag, 2. August 2019, 15:28:06 CEST schrieb YueHaibing:
> Use devm_platform_ioremap_resource() to simplify the code a bit.
> This is detected by coccinelle.
>
> Reported-by: Hulk Robot <hulkci@huawei.com>
> Signed-off-by: YueHaibing <yuehaibing@huawei.com>
looks like nice and simple improvement
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Thanks
Heiko
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v3] tracing: Function stack size and its name mismatch in arm64
From: Steven Rostedt @ 2019-08-02 16:11 UTC (permalink / raw)
To: Jiping Ma
Cc: catalin.marinas, will.deacon, linux-kernel, mingo, joel,
linux-arm-kernel
In-Reply-To: <20190802120920.3b1f4351@gandalf.local.home>
On Fri, 2 Aug 2019 12:09:20 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:
> On Fri, 2 Aug 2019 11:22:59 -0400
> Steven Rostedt <rostedt@goodmis.org> wrote:
>
> > I think you are not explaining the issue correctly. From looking at the
> > document, I think what you want to say is that the LR is saved *after*
> > the data for the function. Is that correct? If so, then yes, it would
> > cause the stack tracing algorithm to be incorrect.
> >
>
> [..]
>
> > Can someone confirm that this is the real issue?
>
> Does this patch fix your issue?
>
Bah, I hit "attach" instead of "insert" (I wondered why it didn't
insert). Here's the patch without the attachment.
-- Steve
diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
index 5ab5200b2bdc..13a4832cfb00 100644
--- a/arch/arm64/include/asm/ftrace.h
+++ b/arch/arm64/include/asm/ftrace.h
@@ -13,6 +13,7 @@
#define HAVE_FUNCTION_GRAPH_FP_TEST
#define MCOUNT_ADDR ((unsigned long)_mcount)
#define MCOUNT_INSN_SIZE AARCH64_INSN_SIZE
+#define ARCH_RET_ADDR_AFTER_LOCAL_VARS 1
#ifndef __ASSEMBLY__
#include <linux/compat.h>
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c
index 5d16f73898db..050c6bd9beac 100644
--- a/kernel/trace/trace_stack.c
+++ b/kernel/trace/trace_stack.c
@@ -158,6 +158,18 @@ static void check_stack(unsigned long ip, unsigned long *stack)
i++;
}
+#ifdef ARCH_RET_ADDR_AFTER_LOCAL_VARS
+ /*
+ * Most archs store the return address before storing the
+ * function's local variables. But some archs do this backwards.
+ */
+ if (x > 1) {
+ memmove(&stack_trace_index[0], &stack_trace_index[1],
+ sizeof(stack_trace_index[0]) * (x - 1));
+ x--;
+ }
+#endif
+
stack_trace_nr_entries = x;
if (task_stack_end_corrupted(current)) {
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH -next 05/12] crypto: inside-secure - use devm_platform_ioremap_resource() to simplify code
From: Antoine Tenart @ 2019-08-02 16:17 UTC (permalink / raw)
To: YueHaibing
Cc: heiko, gary.hook, clabbe.montjoie, linux-arm-kernel, jamie,
linux-stm32, jesper.nilsson, linux-samsung-soc, herbert, krzk,
linux-rockchip, wens, agross, thomas.lendacky, alexandre.torgue,
antoine.tenart, linux-arm-msm, mripard, linux-mediatek,
lars.persson, matthias.bgg, linux-arm-kernel, linux-kernel,
linux-crypto, mcoquelin.stm32, kgene, davem
In-Reply-To: <20190802132809.8116-6-yuehaibing@huawei.com>
Hello,
On Fri, Aug 02, 2019 at 09:28:02PM +0800, YueHaibing wrote:
> Use devm_platform_ioremap_resource() to simplify the code a bit.
> This is detected by coccinelle.
>
> Reported-by: Hulk Robot <hulkci@huawei.com>
> Signed-off-by: YueHaibing <yuehaibing@huawei.com>
Acked-by: Antoine Tenart <antoine.tenart@bootlin.com>
Thanks,
Antoine
> ---
> drivers/crypto/inside-secure/safexcel.c | 4 +---
> 1 file changed, 1 insertion(+), 3 deletions(-)
>
> diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c
> index d1f60fd..822744d 100644
> --- a/drivers/crypto/inside-secure/safexcel.c
> +++ b/drivers/crypto/inside-secure/safexcel.c
> @@ -999,7 +999,6 @@ static void safexcel_init_register_offsets(struct safexcel_crypto_priv *priv)
> static int safexcel_probe(struct platform_device *pdev)
> {
> struct device *dev = &pdev->dev;
> - struct resource *res;
> struct safexcel_crypto_priv *priv;
> int i, ret;
>
> @@ -1015,8 +1014,7 @@ static int safexcel_probe(struct platform_device *pdev)
>
> safexcel_init_register_offsets(priv);
>
> - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> - priv->base = devm_ioremap_resource(dev, res);
> + priv->base = devm_platform_ioremap_resource(pdev, 0);
> if (IS_ERR(priv->base)) {
> dev_err(dev, "failed to get resource\n");
> return PTR_ERR(priv->base);
> --
> 2.7.4
>
>
--
Antoine Ténart, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH v2 2/2] interconnect: qcom: Add tagging and wake/sleep support for sdm845
From: Georgi Djakov @ 2019-08-02 16:22 UTC (permalink / raw)
To: Evan Green, David Dai
Cc: linux-pm, Sean Sweeney, LKML, Doug Anderson, amit.kucheria,
Bjorn Andersson, grahamr, linux-arm-msm, linux-arm Mailing List
In-Reply-To: <CAE=gft78_zcQT=yxpnPhE=1S-pefqrSL6+cPdG8Sm9Utuza85A@mail.gmail.com>
On 7/31/19 22:06, Evan Green wrote:
> On Tue, Jul 30, 2019 at 5:37 PM David Dai <daidavid1@codeaurora.org> wrote:
>>
>>
>> On 7/30/2019 3:54 PM, Evan Green wrote:
>>> On Thu, Jul 18, 2019 at 10:59 AM David Dai <daidavid1@codeaurora.org> wrote:
>>>> On 7/16/2019 1:15 PM, Evan Green wrote:
>>>>> On Mon, Jul 15, 2019 at 4:34 PM David Dai <daidavid1@codeaurora.org> wrote:
>>>>>> Hi Evan,
>>>>>>
>>>>>> Thanks for the continued help in reviewing these patches!
>>>>> No problem. I want to do more, but haven't found time to do the
>>>>> prerequisite research before jumping into some of the other
>>>>> discussions yet.
>>>>>
>>>>>> On 7/11/2019 10:06 AM, Evan Green wrote:
>>>>>>> Hi Georgi and David,
>>>>>>>
>>>>>>> On Tue, Jun 18, 2019 at 2:17 AM Georgi Djakov <georgi.djakov@linaro.org> wrote:
>>>>>>>> From: David Dai <daidavid1@codeaurora.org>
>>>>>>>>
>>>>>>>> Add support for wake and sleep commands by using a tag to indicate
>>>>>>>> whether or not the aggregate and set requests fall into execution
>>>>>>>> state specific bucket.
>>>>>>>>
>>>>>>>> Signed-off-by: David Dai <daidavid1@codeaurora.org>
>>>>>>>> Signed-off-by: Georgi Djakov <georgi.djakov@linaro.org>
>>>>>>>> ---
>>>>>>>> drivers/interconnect/qcom/sdm845.c | 129 ++++++++++++++++++++++-------
>>>>>>>> 1 file changed, 98 insertions(+), 31 deletions(-)
>>>>>>>>
>>>>>>>> diff --git a/drivers/interconnect/qcom/sdm845.c b/drivers/interconnect/qcom/sdm845.c
>>>>>>>> index fb526004c82e..c100aab39415 100644
>>>>>>>> --- a/drivers/interconnect/qcom/sdm845.c
>>>>>>>> +++ b/drivers/interconnect/qcom/sdm845.c
>>>>>>>> @@ -66,6 +66,17 @@ struct bcm_db {
>>>>>>>> #define SDM845_MAX_BCM_PER_NODE 2
>>>>>>>> #define SDM845_MAX_VCD 10
>>>>>>>>
>>>>>>>> +#define QCOM_ICC_BUCKET_AMC 0
>>>>>>> What is AMC again? Is it the "right now" bucket? Maybe a comment on
>>>>>>> the meaning of this bucket would be helpful.
>>>>>> That's correct. Will add a comment for this.
>>>>>>>> +#define QCOM_ICC_BUCKET_WAKE 1
>>>>>>>> +#define QCOM_ICC_BUCKET_SLEEP 2
>>>>>>>> +#define QCOM_ICC_NUM_BUCKETS 3
>>>>>>>> +#define QCOM_ICC_TAG_AMC BIT(QCOM_ICC_BUCKET_AMC)
>>>>>>>> +#define QCOM_ICC_TAG_WAKE BIT(QCOM_ICC_BUCKET_WAKE)
>>>>>>>> +#define QCOM_ICC_TAG_SLEEP BIT(QCOM_ICC_BUCKET_SLEEP)
>>>>>>>> +#define QCOM_ICC_TAG_ACTIVE_ONLY (QCOM_ICC_TAG_AMC | QCOM_ICC_TAG_WAKE)
>>>>>>>> +#define QCOM_ICC_TAG_ALWAYS (QCOM_ICC_TAG_AMC | QCOM_ICC_TAG_WAKE |\
>>>>>>>> + QCOM_ICC_TAG_SLEEP)
>>>>>>>> +
>>>>>>>> /**
>>>>>>>> * struct qcom_icc_node - Qualcomm specific interconnect nodes
>>>>>>>> * @name: the node name used in debugfs
>>>>>>>> @@ -75,7 +86,9 @@ struct bcm_db {
>>>>>>>> * @channels: num of channels at this node
>>>>>>>> * @buswidth: width of the interconnect between a node and the bus
>>>>>>>> * @sum_avg: current sum aggregate value of all avg bw requests
>>>>>>>> + * @sum_avg_cached: previous sum aggregate value of all avg bw requests
>>>>>>>> * @max_peak: current max aggregate value of all peak bw requests
>>>>>>>> + * @max_peak_cached: previous max aggregate value of all peak bw requests
>>>>>>>> * @bcms: list of bcms associated with this logical node
>>>>>>>> * @num_bcms: num of @bcms
>>>>>>>> */
>>>>>>>> @@ -86,8 +99,10 @@ struct qcom_icc_node {
>>>>>>>> u16 num_links;
>>>>>>>> u16 channels;
>>>>>>>> u16 buswidth;
>>>>>>>> - u64 sum_avg;
>>>>>>>> - u64 max_peak;
>>>>>>>> + u64 sum_avg[QCOM_ICC_NUM_BUCKETS];
>>>>>>>> + u64 sum_avg_cached[QCOM_ICC_NUM_BUCKETS];
>>>>>>>> + u64 max_peak[QCOM_ICC_NUM_BUCKETS];
>>>>>>>> + u64 max_peak_cached[QCOM_ICC_NUM_BUCKETS];
>>>>>>>> struct qcom_icc_bcm *bcms[SDM845_MAX_BCM_PER_NODE];
>>>>>>>> size_t num_bcms;
>>>>>>>> };
>>>>>>>> @@ -112,8 +127,8 @@ struct qcom_icc_bcm {
>>>>>>>> const char *name;
>>>>>>>> u32 type;
>>>>>>>> u32 addr;
>>>>>>>> - u64 vote_x;
>>>>>>>> - u64 vote_y;
>>>>>>>> + u64 vote_x[QCOM_ICC_NUM_BUCKETS];
>>>>>>>> + u64 vote_y[QCOM_ICC_NUM_BUCKETS];
>>>>>>>> bool dirty;
>>>>>>>> bool keepalive;
>>>>>>>> struct bcm_db aux_data;
>>>>>>>> @@ -555,7 +570,7 @@ inline void tcs_cmd_gen(struct tcs_cmd *cmd, u64 vote_x, u64 vote_y,
>>>>>>>> cmd->wait = true;
>>>>>>>> }
>>>>>>>>
>>>>>>>> -static void tcs_list_gen(struct list_head *bcm_list,
>>>>>>>> +static void tcs_list_gen(struct list_head *bcm_list, int bucket,
>>>>>>>> struct tcs_cmd tcs_list[SDM845_MAX_VCD],
>>>>>>>> int n[SDM845_MAX_VCD])
>>>>>>>> {
>>>>>>>> @@ -573,8 +588,8 @@ static void tcs_list_gen(struct list_head *bcm_list,
>>>>>>>> commit = true;
>>>>>>>> cur_vcd_size = 0;
>>>>>>>> }
>>>>>>>> - tcs_cmd_gen(&tcs_list[idx], bcm->vote_x, bcm->vote_y,
>>>>>>>> - bcm->addr, commit);
>>>>>>>> + tcs_cmd_gen(&tcs_list[idx], bcm->vote_x[bucket],
>>>>>>>> + bcm->vote_y[bucket], bcm->addr, commit);
>>>>>>>> idx++;
>>>>>>>> n[batch]++;
>>>>>>>> /*
>>>>>>>> @@ -595,32 +610,39 @@ static void tcs_list_gen(struct list_head *bcm_list,
>>>>>>>>
>>>>>>>> static void bcm_aggregate(struct qcom_icc_bcm *bcm)
>>>>>>>> {
>>>>>>>> - size_t i;
>>>>>>>> - u64 agg_avg = 0;
>>>>>>>> - u64 agg_peak = 0;
>>>>>>>> + size_t i, bucket;
>>>>>>>> + u64 agg_avg[QCOM_ICC_NUM_BUCKETS] = {0};
>>>>>>>> + u64 agg_peak[QCOM_ICC_NUM_BUCKETS] = {0};
>>>>>>>> u64 temp;
>>>>>>>>
>>>>>>>> - for (i = 0; i < bcm->num_nodes; i++) {
>>>>>>>> - temp = bcm->nodes[i]->sum_avg * bcm->aux_data.width;
>>>>>>>> - do_div(temp, bcm->nodes[i]->buswidth * bcm->nodes[i]->channels);
>>>>>>>> - agg_avg = max(agg_avg, temp);
>>>>>>>> + for (bucket = 0; bucket < QCOM_ICC_NUM_BUCKETS; bucket++) {
>>>>>>>> + for (i = 0; i < bcm->num_nodes; i++) {
>>>>>>>> + temp = bcm->nodes[i]->sum_avg_cached[bucket] * bcm->aux_data.width;
>>>>>>>> + do_div(temp, bcm->nodes[i]->buswidth * bcm->nodes[i]->channels);
>>>>>>>> + agg_avg[bucket] = max(agg_avg[bucket], temp);
>>>>>>>>
>>>>>>>> - temp = bcm->nodes[i]->max_peak * bcm->aux_data.width;
>>>>>>>> - do_div(temp, bcm->nodes[i]->buswidth);
>>>>>>> Why is it that this one doesn't have the multiply by
>>>>>>> bcm->nodes[i]->channels again? I can't recall if there was a reason.
>>>>>>> If it's correct maybe it deserves a comment.
>>>>>> I think the rationale behind this is generally for consumers to target a
>>>>>> certain minimum threshold to satisfy some structural latency
>>>>>> requirements as opposed to strictly throughput, and it may be easier for
>>>>>> consumers to reuse certain values to support hitting some minimum NoC
>>>>>> frequencies without having to be concerned with the number of channels
>>>>>> that may change from platform to platform.
>>>>> I was mostly pointing out that sum_avg seems to have the multiply, but
>>>>> max_peak does not. I would have expected those two things to be of the
>>>>> same units, and get the same treatment. Maybe the hardware is taking
>>>>> in different final units for that field, one that is per-channel and
>>>>> one that isn't?
>>>> The hardware isn't treating the values differently. I couldn't find any
>>>> justification other than the intuition mentioned above for the ease of
>>>> voting from the consumer perspective. The consumer would know that this
>>>> peak_bw value results in some floor performance from the system to
>>>> satisfy its latency requirements. The same approach would work if we
>>>> accounted for the number of channels as well, but given that channels
>>>> may vary from platform to platform or even on the same platform that
>>>> shares multiple channel configurations(DDR), it can be difficult for
>>>> consumers to keep track of and have to adjust their votes constantly(to
>>>> try to hit some frequency/latency requirement, this intuition doesn't
>>>> apply for avg_bw since we're concerned with throughput in that case).
>>>>
>>>>>>>> - agg_peak = max(agg_peak, temp);
>>>>>>>> - }
>>>>>>>> + temp = bcm->nodes[i]->max_peak_cached[bucket] * bcm->aux_data.width;
>>>>>>>> + do_div(temp, bcm->nodes[i]->buswidth);
>>>>>>>> + agg_peak[bucket] = max(agg_peak[bucket], temp);
>>>>>>>>
>>>>>>>> - temp = agg_avg * 1000ULL;
>>>>>>>> - do_div(temp, bcm->aux_data.unit);
>>>>>>>> - bcm->vote_x = temp;
>>>>>>>> + bcm->nodes[i]->sum_avg[bucket] = 0;
>>>>>>>> + bcm->nodes[i]->max_peak[bucket] = 0;
>>>>>>> I don't understand the sum_avg vs sum_avg_cached. Here's what I understand:
>>>>>>> 1. qcom_icc_aggregate() does the math from the incoming values on
>>>>>>> sum_avg, and then clobbers sum_avg_cached with those values.
>>>>>>> 2. bcm_aggregate() uses sum_avg_cached in its calculations, then clears sum_avg.
>>>>>>>
>>>>>>> But I don't get why that's needed. Why not just have sum_avg? Wouldn't
>>>>>>> it work the same? Ok, it wouldn't if you ended up calling
>>>>>>> bcm_aggregate() multiple times on the same bcm. But you have a dirty
>>>>>>> flag that prevents this from happening. So I think it's safe to remove
>>>>>>> the cached arrays, and just clear out the sum_avg when you aggregate.
>>>>>> You are correct in that the dirty flag would prevent another repeat of
>>>>>> the bcm_aggregate() call in the same icc_set request. But consider a
>>>>>> following icc_set request on a different node that shares the same BCM,
>>>>>> the next bcm_aggregate() would result in an incorrect aggregate sum_avg
>>>>>> for the BCM since the avg_sum from the previous node(from the previous
>>>>>> icc_set) was cleared out. We need a way to retain the current state of
>>>>>> all nodes to accurately aggregate the bw values for the BCM.
>>>>> I don't get it. qcom_icc_aggregate() clobbers sum_avg_cached. So
>>>>> they're only ever a) equal, like after qcom_icc_aggregate(), or b)
>>>>> sum_avg is zeroed, and sum_avg_cached is its old value. A new
>>>>> icc_set_bw() would call aggregate_requests(), which would clobber
>>>>> sum_avg_cached to sum_avg for every BCM involved. Then the core would
>>>>> call apply_constraints(), then qcom_icc_set(), which would use
>>>>> sum_avg_cached, and clear out sum_avg, being sure with the dirty flag
>>>>> that bcm_aggregate() is only called once per BCM. This all happens
>>>>> under the mutex held in the core. A new request would start the whole
>>>>> thing over, since sum_avg is cleared. It seems to me that flow would
>>>>> work the same with one array as it does with two. Maybe you can walk
>>>>> me through a scenario?
>>>>> -Evan
>>>> Let's walk through the scenario you've just described with the
>>>> assumption that there's only one avg_sum value per node with two
>>>> icc_set_bw() requests on two different nodes(say 2MB for node 1 and 1MB
>>>> for node 2) under the same BCM(say BCM A). The first
>>>> qcom_icc_aggregate() aggregates to a 2MB avg_sum at the node1 followed
>>>> by apply_constraints(), qcom_icc_set(), bcm_aggregate() which causes BCM
>>>> A to aggregate to max(node1->avg_sum, node2->avg_sum) and reach a vote_x
>>>> of 2MB(for simplicity let's ignore unit). We then clear out
>>>> node1->avg_sum before we start the next icc_set_bw(). In the following
>>>> icc_set_bw(), the qcom_icc_aggregate() aggregates to 1MB in node2
>>>> followed by apply_constraints(), qcom_icc_set(), bcm_aggregate(), but
>>>> now incorrectly aggregates BCM A to 1MB by looking at
>>>> max(node1->avg_sum, node2->avg_sum) because node1->avg_sum was cleared
>>>> out when in reality BCM A should have a vote_x value of 2MB at this
>>>> point. The subsequent bcm_aggregate do not re-aggregate all of the
>>>> requests for each of its nodes, but assumes that the aggregated results
>>>> at the nodes are correct.
>>> Ah, I finally get it. Thanks for the detailed explanation. It's pretty
>>> confusing that there are essentially two connected graphs laid on top
>>> of each other, one graph consisting of nodes the framework deals with,
>>> and another graph that groups those nodes together into BCMs. I was
>>> failing to understand that bcm_aggregate loops over nodes that have
>>> nothing to do with the current request, and so it needs to remember
>>> the old totals from former requests. You've got the two arrays
>>> basically to differentiate between "add together all requests for this
>>> node", and "max all nodes into a BCM", since you need to reset sum_avg
>>> at the start of the first call to qcom_icc_aggregate().
>> Well it's not really two graphs since the BCMs aren't really connected
>> to each other, they only have association with some groups of physical
>> nodes that share a clock domain(There's some nuances here, but let's
>> assume for the sake of simplicity). Their only job is to aggregate to
>> some threshold value and select a performance point and they don't
>> contain any information about the connectivity of the nodes.
>
> Right ok, I see.
>
>>> I had suggested a callback in the core earlier to tell the providers
>>> "I'm about to start aggregating on these nodes", which would have
>>> allowed you to clear sum_avg in that callback and reduce down to one
>>> array. IMO that's a lot easier to understand than these double arrays,
>>> but maybe it's just me that gets confused.
>> I do admit looking at this is somewhat confusing. I'm not totally
>> against the idea of adding another callback in the framework, maybe we
>> can re-evaluate this when there are other providers using the
>> interconnect framework. I'd prefer to have the justification of needing
>> additional ops in the core if somehow there's some hardware out there
>> that dictates that we need some pre or post aggregation stage as opposed
>> to easier book keeping? Though I do like the idea of reducing complexity
>> overall, any thoughts on this Georgi?
>
> Sure. I suppose any other SoC that does this same grouping thing in
> the hardware will end up duplicating this same complexity. We'll see
> if anybody has anything like this. It also might end up being useful
> even if it's just for QC SoCs if we find ourselves copy/pasting a lot
> of this logic in sdm845.c for sdm-next.c. Generally we should aim to
> keep the providers as dumb as we can, but I'm fine waiting until
> there's something to refactor down.
If this same logic would be re-used in the upcoming SoCs and adding a single
callback would simplify the providers significantly, then let's do it and try to
keep the complexity at minimum from the beginning. Will give it a try.
Thanks,
Georgi
>>>
>>> Why do we bother with the individual nodes at all, why don't we just
>>> build a graph out of the BCMs themselves and pass that to the
>>> framework? I guess you can't do that because of .channels and
>>> .bus_width, you wouldn't know what to multiply/divide by to translate
>>> to a vote value? Hm... it would be great to make this simpler, but I'm
>>> out of suggestions for now.
>>
>> I appreciate the thought, but not only do the nodes provide the
>> width/channel, they provide all the connectivity data and an accurate
>> representation of the NoC topology. There's no way to aggregate the
>> nodes and the paths properly if we lose out on the granularity that the
>> current graph provides(Imagine the example of two nodes on some mutually
>> exclusive path under the same BCM again using avg_bw, 1MBps on node1 and
>> 1MBps node2 should result in an aggregate BCM node of 1MBps since they
>> physically don't share the same port where as if we clobbered the nodes
>> together and represent them under a single BCM, it would suggest that
>> they share the same physical port and aggregate 2MBps when in reality
>> they don't need to be since they are parallel).
>
> Oh right, that makes sense. I'm on board.
> -Evan
>
>>
>>> -Evan
>>>
>>>>>>>> + }
>>>>>>>>
>>>>>>>> - temp = agg_peak * 1000ULL;
>>>>>>>> - do_div(temp, bcm->aux_data.unit);
>>>>>>>> - bcm->vote_y = temp;
>>>>>>>> + temp = agg_avg[bucket] * 1000ULL;
>>>>>>>> + do_div(temp, bcm->aux_data.unit);
>>>>>>>> + bcm->vote_x[bucket] = temp;
>>>>>>>>
>>>>>>>> - if (bcm->keepalive && bcm->vote_x == 0 && bcm->vote_y == 0) {
>>>>>>>> - bcm->vote_x = 1;
>>>>>>>> - bcm->vote_y = 1;
>>>>>>>> + temp = agg_peak[bucket] * 1000ULL;
>>>>>>>> + do_div(temp, bcm->aux_data.unit);
>>>>>>>> + bcm->vote_y[bucket] = temp;
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + if (bcm->keepalive && bcm->vote_x[0] == 0 && bcm->vote_y[0] == 0) {
>>>>>>>> + bcm->vote_x[QCOM_ICC_BUCKET_AMC] = 1;
>>>>>>>> + bcm->vote_x[QCOM_ICC_BUCKET_WAKE] = 1;
>>>>>>>> + bcm->vote_y[QCOM_ICC_BUCKET_AMC] = 1;
>>>>>>>> + bcm->vote_y[QCOM_ICC_BUCKET_WAKE] = 1;
>>>>>>>> }
>>>>>>>>
>>>>>>>> bcm->dirty = false;
>>>>>>>> @@ -631,15 +653,25 @@ static int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
>>>>>>>> {
>>>>>>>> size_t i;
>>>>>>>> struct qcom_icc_node *qn;
>>>>>>>> + unsigned long tag_word = (unsigned long)tag;
>>>>>>>>
>>>>>>>> qn = node->data;
>>>>>>>>
>>>>>>>> + if (!tag)
>>>>>>>> + tag_word = QCOM_ICC_TAG_ALWAYS;
>>>>>>>> +
>>>>>>>> + for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
>>>>>>>> + if (test_bit(i, &tag_word)) {
>>>>>>> I guess all this extra business with tag_word and casting is so that
>>>>>>> you can use test_bit, which is presumably a tiny bit faster? Does this
>>>>>>> actually make a measurable difference? Maybe in the name of simplicity
>>>>>>> we just do if (tag & BIT(i)), and then optimize if we find that
>>>>>>> conditional to be a hotspot?
>>>>>> Using (tag & BIT(i)) as opposed to test_bit seems reasonable to me.
>>>>>>>> + qn->sum_avg[i] += avg_bw;
>>>>>>>> + qn->max_peak[i] = max_t(u32, qn->max_peak[i], peak_bw);
>>>>>>>> + qn->sum_avg_cached[i] = qn->sum_avg[i];
>>>>>>>> + qn->max_peak_cached[i] = qn->max_peak[i];
>>>>>>>> + }
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> *agg_avg += avg_bw;
>>>>>>>> *agg_peak = max_t(u32, *agg_peak, peak_bw);
>>>>>>>>
>>>>>>>> - qn->sum_avg = *agg_avg;
>>>>>>>> - qn->max_peak = *agg_peak;
>>>>>>>> -
>>>>>>>> for (i = 0; i < qn->num_bcms; i++)
>>>>>>>> qn->bcms[i]->dirty = true;
>>>>>>>>
>>>>>>>> @@ -675,7 +707,7 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
>>>>>>>> * Construct the command list based on a pre ordered list of BCMs
>>>>>>>> * based on VCD.
>>>>>>>> */
>>>>>>>> - tcs_list_gen(&commit_list, cmds, commit_idx);
>>>>>>>> + tcs_list_gen(&commit_list, QCOM_ICC_BUCKET_AMC, cmds, commit_idx);
>>>>>>>>
>>>>>>>> if (!commit_idx[0])
>>>>>>>> return ret;
>>>>>>>> @@ -693,6 +725,41 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
>>>>>>>> return ret;
>>>>>>>> }
>>>>>>>>
>>>>>>>> + INIT_LIST_HEAD(&commit_list);
>>>>>>>> +
>>>>>>>> + for (i = 0; i < qp->num_bcms; i++) {
>>>>>>>> + /*
>>>>>>>> + * Only generate WAKE and SLEEP commands if a resource's
>>>>>>>> + * requirements change as the execution environment transitions
>>>>>>>> + * between different power states.
>>>>>>>> + */
>>>>>>>> + if (qp->bcms[i]->vote_x[QCOM_ICC_BUCKET_WAKE] !=
>>>>>>>> + qp->bcms[i]->vote_x[QCOM_ICC_BUCKET_SLEEP] ||
>>>>>>>> + qp->bcms[i]->vote_y[QCOM_ICC_BUCKET_WAKE] !=
>>>>>>>> + qp->bcms[i]->vote_y[QCOM_ICC_BUCKET_SLEEP]) {
>>>>>>>> + list_add_tail(&qp->bcms[i]->list, &commit_list);
>>>>>>>> + }
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + if (list_empty(&commit_list))
>>>>>>>> + return ret;
>>>>>>>> +
>>>>>>>> + tcs_list_gen(&commit_list, QCOM_ICC_BUCKET_WAKE, cmds, commit_idx);
>>>>>>>> +
>>>>>>>> + ret = rpmh_write_batch(qp->dev, RPMH_WAKE_ONLY_STATE, cmds, commit_idx);
>>>>>>>> + if (ret) {
>>>>>>>> + pr_err("Error sending WAKE RPMH requests (%d)\n", ret);
>>>>>>>> + return ret;
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> + tcs_list_gen(&commit_list, QCOM_ICC_BUCKET_SLEEP, cmds, commit_idx);
>>>>>>>> +
>>>>>>>> + ret = rpmh_write_batch(qp->dev, RPMH_SLEEP_STATE, cmds, commit_idx);
>>>>>>>> + if (ret) {
>>>>>>>> + pr_err("Error sending SLEEP RPMH requests (%d)\n", ret);
>>>>>>>> + return ret;
>>>>>>>> + }
>>>>>>>> +
>>>>>>>> return ret;
>>>>>>>> }
>>>>>>>>
>>>>>> --
>>>>>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
>>>>>> a Linux Foundation Collaborative Project
>>>>>>
>>>> --
>>>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
>>>> a Linux Foundation Collaborative Project
>>>>
>> --
>> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
>> a Linux Foundation Collaborative Project
>>
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v3 01/11] kselftest: arm64: introduce new boilerplate code
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin
In-Reply-To: <20190802170300.20662-1-cristian.marussi@arm.com>
Added a new arm64-specific empty subsystem amongst TARGETS of KSFT build
framework; once populated with testcases, it will be possible to build
and invoke the new KSFT TARGETS=arm64 related tests from the toplevel
Makefile in the usual ways.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
Reviewed the build instructions reported in the README, to be more
agnostic regarding user/device etc..
---
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/arm64/Makefile | 51 ++++++++++++++++++++++++++
tools/testing/selftests/arm64/README | 43 ++++++++++++++++++++++
3 files changed, 95 insertions(+)
create mode 100644 tools/testing/selftests/arm64/Makefile
create mode 100644 tools/testing/selftests/arm64/README
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 25b43a8c2b15..1722dae9381a 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
TARGETS = android
+TARGETS += arm64
TARGETS += bpf
TARGETS += breakpoints
TARGETS += capabilities
diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
new file mode 100644
index 000000000000..03a0d4f71218
--- /dev/null
+++ b/tools/testing/selftests/arm64/Makefile
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2019 ARM Limited
+
+# When ARCH not overridden for crosscompiling, lookup machine
+ARCH ?= $(shell uname -m)
+ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
+
+ifeq ("x$(ARCH)", "xarm64")
+SUBDIRS :=
+else
+SUBDIRS :=
+endif
+
+CFLAGS := -Wall -O2 -g
+
+export CC
+export CFLAGS
+
+all:
+ @for DIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ mkdir -p $$BUILD_TARGET; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+install: all
+ @for DIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+run_tests: all
+ @for DIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+# Avoid any output on non arm64 on emit_tests
+emit_tests: all
+ @for DIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+clean:
+ @for DIR in $(SUBDIRS); do \
+ BUILD_TARGET=$(OUTPUT)/$$DIR; \
+ make OUTPUT=$$BUILD_TARGET -C $$DIR $@; \
+ done
+
+.PHONY: all clean install run_tests emit_tests
diff --git a/tools/testing/selftests/arm64/README b/tools/testing/selftests/arm64/README
new file mode 100644
index 000000000000..dee3306071cc
--- /dev/null
+++ b/tools/testing/selftests/arm64/README
@@ -0,0 +1,43 @@
+KSelfTest ARM64
+===============
+
+- These tests are arm64 specific and so not built or run but just skipped
+ completely when env-variable ARCH is found to be different than 'arm64'
+ and `uname -m` reports other than 'aarch64'.
+
+- Holding true the above, ARM64 KSFT tests can be run:
+
+ + as standalone (example for signal tests)
+
+ $ make -C tools/testing/selftest/arm64/signal \
+ INSTALL_PATH=<your-installation-path> install
+
+ and then launching on the target device inside the installed path:
+
+ $ <your-installed-path>/test_arm64_signals.sh [-k | -v]
+
+ + within the KSelfTest framework using standard Linux top-level-makefile
+ targets:
+
+ $ make TARGETS=arm64 kselftest-clean
+ $ make TARGETS=arm64 kselftest
+
+ Further details on building and running KFST can be found in:
+ Documentation/dev-tools/kselftest.rst
+
+- Tests can depend on some arch-specific definitions which can be found in a
+ standard Kernel Headers installation in $(top_srcdir)/usr/include.
+ Such Kernel Headers are automatically installed (via make headers_install)
+ by KSFT framework itself in a dedicated directory when tests are launched
+ via KSFT itself; when running standalone, instead, a Warning is issued
+ if such headers cannot be found somewhere (we try to guess a few standard
+ locations anyway)
+
+- Some of these tests may be related to possibly not implemented ARMv8
+ features: depending on their implementation status on the effective HW
+ we'll expect different results. The tests' harness will take care to check
+ at run-time if the required features are supported and will act accordingly.
+ Moreover, in order to avoid any kind of compile-time dependency on the
+ toolchain (possibly due to the above mentioned not-implemented features),
+ we make strictly use of direct 'S3_ sysreg' raw-encoding while checking for
+ those features and/or lookin up sysregs.
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 00/11] Add arm64/signal initial kselftest support
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin
Hi
this patchset aims to add the initial arch-specific arm64 support to
kselftest starting with signals-related test-cases.
A common internal test-case layout is proposed which then it is anyway
wired-up to the toplevel kselftest Makefile, so that it should be possible
at the end to run it on an arm64 target in the usual way with KSFT.
~/linux# make TARGETS=arm64 kselftest
New KSFT arm64 testcases live inside tools/testing/selftests/arm64 grouped by
family inside subdirectories: arm64/signal is the first family proposed with
this series. arm64/signal tests can be run via KSFT or standalone.
Thanks
Cristian
Notes:
-----
- further details in the included READMEs
- more tests still to be written (current strategy is going through the related
Kernel signal-handling code and write a test for each possible and sensible code-path)
A few ideas in testcases/TODO.readme
- a bit of overlap around KSFT arm64/ Makefiles is expected with this:
https://lore.kernel.org/linux-arm-kernel/c1e6aad230658bc175b42d92daeff2e30050302a.1563904656.git.andreyknvl@google.com/
Changes:
--------
v2-->v3:
- rebased on v5.3-rc2
- better test result characterization looking for
SEGV_ACCERR in si_code on SIGSEGV
- using KSFT Framework macros for retvalues
- removed SAFE_WRITE()/dump_uc: buggy, un-needed and unused
- reviewed generation process of test_arm64_signals.sh runner script
- re-added a fixed fake_sigreturn_misaligned_sp testcase and a properly
extended fake_sigreturn() helper
- added tests' TODO notes
v1-->v2:
- rebased on 5.2-rc7
- various makefile's cleanups
- mixed READMEs fixes
- fixed test_arm64_signals.sh runner script
- cleaned up assembly code in signal.S
- improved get_current_context() logic
- fixed SAFE_WRITE()
- common support code splitted into more chunks, each one introduced when
needed by some new testcases
- fixed some headers validation routines in testcases.c
- removed some still broken/immature tests:
+ fake_sigreturn_misaligned
+ fake_sigreturn_overflow_reserved
+ mangle_pc_invalid
+ mangle_sp_misaligned
- fixed some other testcases:
+ mangle_pstate_ssbs_regs: better checks of SSBS bit when feature unsupported
+ mangle_pstate_invalid_compat_toggle: name fix
+ mangle_pstate_invalid_mode_el[1-3]: precautionary zeroing PSTATE.MODE
+ fake_sigreturn_bad_magic, fake_sigreturn_bad_size,
fake_sigreturn_bad_size_for_magic0:
- accounting for available space...dropping extra when needed
- keeping alignent
- new testcases on FPSMID context:
+ fake_sigreturn_missing_fpsimd
+ fake_sigreturn_duplicated_fpsimd
Cristian Marussi (11):
kselftest: arm64: introduce new boilerplate code
kselftest: arm64: adds first test and common utils
kselftest: arm64: mangle_pstate_invalid_daif_bits
kselftest: arm64: mangle_pstate_invalid_mode_el
kselftest: arm64: mangle_pstate_ssbs_regs
kselftest: arm64: fake_sigreturn_bad_magic
kselftest: arm64: fake_sigreturn_bad_size_for_magic0
kselftest: arm64: fake_sigreturn_missing_fpsimd
kselftest: arm64: fake_sigreturn_duplicated_fpsimd
kselftest: arm64: fake_sigreturn_bad_size
kselftest: arm64: fake_sigreturn_misaligned_sp
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/arm64/Makefile | 51 +++
tools/testing/selftests/arm64/README | 43 +++
.../testing/selftests/arm64/signal/.gitignore | 6 +
tools/testing/selftests/arm64/signal/Makefile | 88 +++++
tools/testing/selftests/arm64/signal/README | 59 +++
.../testing/selftests/arm64/signal/signals.S | 73 ++++
.../arm64/signal/test_arm64_signals.src_shell | 55 +++
.../selftests/arm64/signal/test_signals.c | 26 ++
.../selftests/arm64/signal/test_signals.h | 141 +++++++
.../arm64/signal/test_signals_utils.c | 354 ++++++++++++++++++
.../arm64/signal/test_signals_utils.h | 16 +
.../arm64/signal/testcases/.gitignore | 11 +
.../arm64/signal/testcases/TODO.readme | 7 +
.../testcases/fake_sigreturn_bad_magic.c | 63 ++++
.../testcases/fake_sigreturn_bad_size.c | 85 +++++
.../fake_sigreturn_bad_size_for_magic0.c | 57 +++
.../fake_sigreturn_duplicated_fpsimd.c | 62 +++
.../testcases/fake_sigreturn_misaligned_sp.c | 30 ++
.../testcases/fake_sigreturn_missing_fpsimd.c | 44 +++
.../mangle_pstate_invalid_compat_toggle.c | 25 ++
.../mangle_pstate_invalid_daif_bits.c | 28 ++
.../mangle_pstate_invalid_mode_el1.c | 29 ++
.../mangle_pstate_invalid_mode_el2.c | 29 ++
.../mangle_pstate_invalid_mode_el3.c | 29 ++
.../testcases/mangle_pstate_ssbs_regs.c | 56 +++
.../arm64/signal/testcases/testcases.c | 150 ++++++++
.../arm64/signal/testcases/testcases.h | 83 ++++
28 files changed, 1701 insertions(+)
create mode 100644 tools/testing/selftests/arm64/Makefile
create mode 100644 tools/testing/selftests/arm64/README
create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
create mode 100644 tools/testing/selftests/arm64/signal/Makefile
create mode 100644 tools/testing/selftests/arm64/signal/README
create mode 100644 tools/testing/selftests/arm64/signal/signals.S
create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
create mode 100644 tools/testing/selftests/arm64/signal/testcases/TODO.readme
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v3 03/11] kselftest: arm64: mangle_pstate_invalid_daif_bits
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin
In-Reply-To: <20190802170300.20662-1-cristian.marussi@arm.com>
Added a simple mangle testcase which messes with the ucontext_t
from within the sig_handler, trying to set PSTATE DAIF bits to an
invalid value (masking everything). Expects SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../arm64/signal/testcases/.gitignore | 1 +
.../mangle_pstate_invalid_daif_bits.c | 28 +++++++++++++++++++
2 files changed, 29 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 8651272e3cfc..8a0a29f0cc2a 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -1 +1,2 @@
mangle_pstate_invalid_compat_toggle
+mangle_pstate_invalid_daif_bits
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
new file mode 100644
index 000000000000..af899d4bb655
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_daif_bits.c
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+ ucontext_t *uc)
+{
+ ASSERT_GOOD_CONTEXT(uc);
+
+ /*
+ * This config should trigger a SIGSEGV by Kernel when it checks
+ * the sigframe consistency in valid_user_regs() routine.
+ */
+ uc->uc_mcontext.pstate |= PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT;
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .sanity_disabled = true,
+ .name = "MANGLE_PSTATE_INVALID_DAIF_BITS",
+ .descr = "Mangling uc_mcontext with INVALID DAIF_BITS",
+ .sig_trig = SIGUSR1,
+ .sig_ok = SIGSEGV,
+ .run = mangle_invalid_pstate_run,
+};
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 04/11] kselftest: arm64: mangle_pstate_invalid_mode_el
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin
In-Reply-To: <20190802170300.20662-1-cristian.marussi@arm.com>
Added 3 simple mangle testcases that mess with the ucontext_t
from within the sig_handler, trying to toggle PSTATE mode bits to
trick the system into switching to EL1/EL2/EL3. Expects SIGSEGV
on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../arm64/signal/testcases/.gitignore | 3 ++
.../mangle_pstate_invalid_mode_el1.c | 29 +++++++++++++++++++
.../mangle_pstate_invalid_mode_el2.c | 29 +++++++++++++++++++
.../mangle_pstate_invalid_mode_el3.c | 29 +++++++++++++++++++
4 files changed, 90 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 8a0a29f0cc2a..226bb179b673 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -1,2 +1,5 @@
mangle_pstate_invalid_compat_toggle
mangle_pstate_invalid_daif_bits
+mangle_pstate_invalid_mode_el1
+mangle_pstate_invalid_mode_el2
+mangle_pstate_invalid_mode_el3
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
new file mode 100644
index 000000000000..07aed7624383
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el1.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+ ucontext_t *uc)
+{
+ ASSERT_GOOD_CONTEXT(uc);
+
+ /*
+ * This config should trigger a SIGSEGV by Kernel
+ * when checking valid_user_regs()
+ */
+ uc->uc_mcontext.pstate &= ~PSR_MODE_MASK;
+ uc->uc_mcontext.pstate |= PSR_MODE_EL1t;
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .sanity_disabled = true,
+ .name = "MANGLE_PSTATE_INVALID_MODE_EL1t",
+ .descr = "Mangling uc_mcontext with INVALID MODE EL1t",
+ .sig_trig = SIGUSR1,
+ .sig_ok = SIGSEGV,
+ .run = mangle_invalid_pstate_run,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
new file mode 100644
index 000000000000..0fe7f69efb33
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el2.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+ ucontext_t *uc)
+{
+ ASSERT_GOOD_CONTEXT(uc);
+
+ /*
+ * This config should trigger a SIGSEGV by Kernel
+ * when checking valid_user_regs()
+ */
+ uc->uc_mcontext.pstate &= ~PSR_MODE_MASK;
+ uc->uc_mcontext.pstate |= PSR_MODE_EL2t;
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .sanity_disabled = true,
+ .name = "MANGLE_PSTATE_INVALID_MODE_EL2t",
+ .descr = "Mangling uc_mcontext with INVALID MODE EL2t",
+ .sig_trig = SIGUSR1,
+ .sig_ok = SIGSEGV,
+ .run = mangle_invalid_pstate_run,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
new file mode 100644
index 000000000000..61131dd6ca0c
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_mode_el3.c
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+ ucontext_t *uc)
+{
+ ASSERT_GOOD_CONTEXT(uc);
+
+ /*
+ * This config should trigger a SIGSEGV by Kernel
+ * when checking valid_user_regs()
+ */
+ uc->uc_mcontext.pstate &= ~PSR_MODE_MASK;
+ uc->uc_mcontext.pstate |= PSR_MODE_EL3t;
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .sanity_disabled = true,
+ .name = "MANGLE_PSTATE_INVALID_MODE_EL3t",
+ .descr = "Mangling uc_mcontext with INVALID MODE EL3t",
+ .sig_trig = SIGUSR1,
+ .sig_ok = SIGSEGV,
+ .run = mangle_invalid_pstate_run,
+};
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 05/11] kselftest: arm64: mangle_pstate_ssbs_regs
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin
In-Reply-To: <20190802170300.20662-1-cristian.marussi@arm.com>
Added a simple mangle testcase which messes with the ucontext_t
from within the sig_handler, trying to toggle PSTATE SSBS bit.
Expect SIGILL if SSBS feature unsupported or that the value set in
PSTATE.SSBS is preserved on test PASS.
This commit also introduces a new common utility function:
get_current_context() which can be used to grab a ucontext without
the help of libc, and detect if such ucontext has been actively used
to jump back into it.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../selftests/arm64/signal/test_signals.h | 4 +
.../arm64/signal/test_signals_utils.c | 93 +++++++++++++++++++
.../arm64/signal/test_signals_utils.h | 2 +
.../arm64/signal/testcases/.gitignore | 1 +
.../testcases/mangle_pstate_ssbs_regs.c | 56 +++++++++++
5 files changed, 156 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
index 85db3ac44b32..37bed0590226 100644
--- a/tools/testing/selftests/arm64/signal/test_signals.h
+++ b/tools/testing/selftests/arm64/signal/test_signals.h
@@ -116,6 +116,10 @@ struct tdescr {
/* optional sa_flags for the installed handler */
int sa_flags;
ucontext_t saved_uc;
+ /* used by get_current_ctx() */
+ size_t live_sz;
+ ucontext_t *live_uc;
+ volatile bool live_uc_valid;
/* a setup function to be called before test starts */
int (*setup)(struct tdescr *td);
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
index ac0055f6340b..faf55ba99d58 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.c
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
@@ -11,12 +11,16 @@
#include <linux/auxvec.h>
#include <ucontext.h>
+#include <asm/unistd.h>
+
#include "test_signals.h"
#include "test_signals_utils.h"
#include "testcases/testcases.h"
extern struct tdescr *current;
+static int sig_copyctx = SIGUSR2;
+
static char *feats_store[FMAX_END] = {
"SSBS",
"PAN",
@@ -37,6 +41,85 @@ static inline char *feats_to_string(unsigned long feats)
return feats_string;
}
+/*
+ * Obtaining a valid and full-blown ucontext_t from userspace is tricky:
+ * libc getcontext does() not save all the regs and messes with some of
+ * them (pstate value in particular is not reliable).
+ * Here we use a service signal to grab the ucontext_t from inside a
+ * dedicated signal handler, since there, it is populated by Kernel
+ * itself in setup_sigframe(). The grabbed context is then stored and
+ * made available in td->live_uc.
+ *
+ * Anyway this function really serves a dual purpose:
+ *
+ * 1. grab a valid sigcontext into td->live_uc for result analysis: in
+ * such case it returns 1.
+ *
+ * 2. detect if somehow a previously grabbed live_uc context has been
+ * used actively with a sigreturn: in such a case the execution would have
+ * magically resumed in the middle of the function itself (seen_already==1):
+ * in such a case return 0, since in fact we have not just simply grabbed
+ * the context.
+ *
+ * This latter case is useful to detect when a fake_sigreturn test-case has
+ * unexpectedly survived without hittig a SEGV.
+ */
+bool get_current_context(struct tdescr *td, ucontext_t *dest_uc)
+{
+ static volatile sig_atomic_t seen_already;
+
+ if (!td || !dest_uc) {
+ fprintf(stdout, "Signal-based Context dumping NOT available\n");
+ return 0;
+ }
+
+ /* it's a genuine invokation..reinit */
+ seen_already = 0;
+ td->live_uc_valid = 0;
+ td->live_sz = sizeof(*dest_uc);
+ memset(dest_uc, 0x00, td->live_sz);
+ td->live_uc = dest_uc;
+ /*
+ * Grab ucontext_t triggering a signal...
+ * ASM equivalent of raise(sig_copyctx);
+ *
+ * Note that:
+ * - live_uc_valid is declared volatile in struct tdescr
+ * since it will be changed inside the sig_copyctx handler.
+ * - the kill() syscall invocation returns only after any possible
+ * registered sig_handler for the invoked signal has returned,
+ * so that live_uc_valid flag is surely up to date when this
+ * function return it.
+ * - the additional 'memory' clobber is there to avoid possible
+ * compiler's assumption on the content pointed by dest_uc, which
+ * is changed inside the handler, but not referenced here anyway.
+ */
+ asm volatile ("mov x8, %0\n\t"
+ "svc #0\n\t"
+ "mov x1, %1\n\t"
+ "mov x8, %2\n\t"
+ "svc #0"
+ :
+ : "i" (__NR_getpid),
+ "r" (sig_copyctx),
+ "i" (__NR_kill)
+ : "x1","x8","x0","memory");
+ /*
+ * If we get here with seen_already==1 it implies the td->live_uc
+ * context has been used to get back here....this probably means
+ * a test has failed to cause a SEGV...anyway the live_uc has not
+ * just been acquired...so return 0
+ */
+ if (seen_already) {
+ fprintf(stdout,
+ "Successful sigreturn detected: live_uc is stale !\n");
+ return 0;
+ }
+ seen_already = 1;
+
+ return td->live_uc_valid;
+}
+
static void unblock_signal(int signum)
{
sigset_t sset;
@@ -112,6 +195,12 @@ static void default_handler(int signum, siginfo_t *si, void *uc)
* to terminate immediately exiting straight away
*/
default_result(current, 1);
+ } else if (signum == sig_copyctx && current->live_uc) {
+ memcpy(current->live_uc, uc, current->live_sz);
+ ASSERT_GOOD_CONTEXT(current->live_uc);
+ current->live_uc_valid = 1;
+ fprintf(stderr,
+ "GOOD CONTEXT grabbed from sig_copyctx handler\n");
} else {
if (signum == current->sig_unsupp && !are_feats_ok(current)) {
fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
@@ -214,6 +303,10 @@ static int test_init(struct tdescr *td)
!feats_ok ? "NOT " : "");
}
+ if (td->sig_trig == sig_copyctx)
+ sig_copyctx = SIGUSR1;
+ unblock_signal(sig_copyctx);
+
td->initialized = 1;
return 1;
}
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
index 8658d1a7d4b9..ce35be8ebc8e 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -10,4 +10,6 @@ int test_setup(struct tdescr *td);
void test_cleanup(struct tdescr *td);
int test_run(struct tdescr *td);
void test_result(struct tdescr *td);
+
+bool get_current_context(struct tdescr *td, ucontext_t *dest_uc);
#endif
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 226bb179b673..a48a118b1a1a 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -3,3 +3,4 @@ mangle_pstate_invalid_daif_bits
mangle_pstate_invalid_mode_el1
mangle_pstate_invalid_mode_el2
mangle_pstate_invalid_mode_el3
+mangle_pstate_ssbs_regs
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
new file mode 100644
index 000000000000..a399d9aa40d5
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_ssbs_regs.c
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_ssbs_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ ASSERT_GOOD_CONTEXT(uc);
+
+ /* set bit value */
+ uc->uc_mcontext.pstate |= PSR_SSBS_BIT;
+ fprintf(stderr, "SSBS set to 1 -- PSTATE: 0x%016lX\n",
+ uc->uc_mcontext.pstate);
+ /* Save after mangling...it should be preserved */
+ td->saved_uc = *uc;
+
+ return 1;
+}
+
+static void pstate_ssbs_bit_checks(struct tdescr *td)
+{
+ uint64_t val = 0;
+ ucontext_t uc;
+
+ /* This check reports some result even if MRS SSBS unsupported */
+ if (get_current_context(td, &uc))
+ fprintf(stderr,
+ "INFO: live_uc - got PSTATE: 0x%016lX -> SSBS %s\n",
+ uc.uc_mcontext.pstate,
+ (td->saved_uc.uc_mcontext.pstate & PSR_SSBS_BIT) ==
+ (uc.uc_mcontext.pstate & PSR_SSBS_BIT) ?
+ "PRESERVED" : "CLEARED");
+
+ fprintf(stderr, "Checking with MRS SSBS...\n");
+ get_regval(S3_MRS_SSBS_SYSREG, val);
+ fprintf(stderr, "INFO: MRS SSBS - got: 0x%016lX\n", val);
+ /* pass when preserved */
+ td->pass = (val & PSR_SSBS_BIT) ==
+ (td->saved_uc.uc_mcontext.pstate & PSR_SSBS_BIT);
+}
+
+struct tdescr tde = {
+ .sanity_disabled = true,
+ .name = "MANGLE_PSTATE_SSBS_REGS",
+ .descr = "Mangling uc_mcontext changing SSBS.(PRESERVE)",
+ .feats_required = FEAT_SSBS,
+ .sig_trig = SIGUSR1,
+ .sig_unsupp = SIGILL,
+ .run = mangle_invalid_pstate_ssbs_run,
+ .check_result = pstate_ssbs_bit_checks,
+};
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 02/11] kselftest: arm64: adds first test and common utils
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin
In-Reply-To: <20190802170300.20662-1-cristian.marussi@arm.com>
Added some arm64/signal specific boilerplate and utility code to help
further testcase development.
A simple testcase and related helpers are also introduced in this commit:
mangle_pstate_invalid_compat_toggle is a simple mangle testcase which
messes with the ucontext_t from within the sig_handler, trying to toggle
PSTATE state bits to switch the system between 32bit/64bit execution state.
Expects SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
A few fixes:
- test_arm64_signals.sh runner script generation has been reviewed in order to
be safe against the .gitignore
- using kselftest.h officially provided defines for tests' return values
- removed SAFE_WRITE()/dump_uc()
- looking for si_code==SEGV_ACCERR on SEGV test cases to better understand if
the sigfault had been directly triggered by Kernel
---
tools/testing/selftests/arm64/Makefile | 2 +-
.../testing/selftests/arm64/signal/.gitignore | 6 +
tools/testing/selftests/arm64/signal/Makefile | 88 ++++++
tools/testing/selftests/arm64/signal/README | 59 ++++
.../arm64/signal/test_arm64_signals.src_shell | 55 ++++
.../selftests/arm64/signal/test_signals.c | 26 ++
.../selftests/arm64/signal/test_signals.h | 137 +++++++++
.../arm64/signal/test_signals_utils.c | 261 ++++++++++++++++++
.../arm64/signal/test_signals_utils.h | 13 +
.../arm64/signal/testcases/.gitignore | 1 +
.../mangle_pstate_invalid_compat_toggle.c | 25 ++
.../arm64/signal/testcases/testcases.c | 150 ++++++++++
.../arm64/signal/testcases/testcases.h | 83 ++++++
13 files changed, 905 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/arm64/signal/.gitignore
create mode 100644 tools/testing/selftests/arm64/signal/Makefile
create mode 100644 tools/testing/selftests/arm64/signal/README
create mode 100755 tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
create mode 100644 tools/testing/selftests/arm64/signal/test_signals.c
create mode 100644 tools/testing/selftests/arm64/signal/test_signals.h
create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.c
create mode 100644 tools/testing/selftests/arm64/signal/test_signals_utils.h
create mode 100644 tools/testing/selftests/arm64/signal/testcases/.gitignore
create mode 100644 tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.c
create mode 100644 tools/testing/selftests/arm64/signal/testcases/testcases.h
diff --git a/tools/testing/selftests/arm64/Makefile b/tools/testing/selftests/arm64/Makefile
index 03a0d4f71218..af59dc74e0dc 100644
--- a/tools/testing/selftests/arm64/Makefile
+++ b/tools/testing/selftests/arm64/Makefile
@@ -6,7 +6,7 @@ ARCH ?= $(shell uname -m)
ARCH := $(shell echo $(ARCH) | sed -e s/aarch64/arm64/)
ifeq ("x$(ARCH)", "xarm64")
-SUBDIRS :=
+SUBDIRS := signal
else
SUBDIRS :=
endif
diff --git a/tools/testing/selftests/arm64/signal/.gitignore b/tools/testing/selftests/arm64/signal/.gitignore
new file mode 100644
index 000000000000..434f65c15f03
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/.gitignore
@@ -0,0 +1,6 @@
+# Helper script's internal testcases list (TPROGS) is regenerated
+# each time by Makefile on standalone (non KSFT driven) runs.
+# Committing such list creates a dependency between testcases
+# patches such that they are no more easily revertable. Just ignore.
+test_arm64_signals.src_shell
+test_arm64_signals.sh
diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
new file mode 100644
index 000000000000..8c8d08be4b0d
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/Makefile
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2019 ARM Limited
+
+# Supports also standalone invokation out of KSFT-tree
+# Compile standalone and run on your device with:
+#
+# $ make -C tools/testing/selftests/arm64/signal INSTALL_PATH=<your-dir> install
+#
+# Run standalone on device with:
+#
+# $ <your-device-instdir>/test_arm64_signals.sh [-k|-v]
+#
+# If INSTALL_PATH= is NOT provided it will default to ./install
+
+# A proper top_srcdir is needed both by KSFT(lib.mk)
+# and standalone builds
+top_srcdir = ../../../../..
+
+CFLAGS += -std=gnu99 -I. -I$(top_srcdir)/tools/testing/selftests/
+SRCS := $(filter-out testcases/testcases.c,$(wildcard testcases/*.c))
+PROGS := $(patsubst %.c,%,$(SRCS))
+
+# Guessing as best as we can where the Kernel headers
+# could have been installed depending on ENV config and
+# type of invocation.
+ifeq ($(KBUILD_OUTPUT),)
+khdr_dir = $(top_srcdir)/usr/include
+else
+ifeq (0,$(MAKELEVEL))
+khdr_dir = $(KBUILD_OUTPUT)/usr/include
+else
+# the KSFT preferred location when KBUILD_OUTPUT is set
+khdr_dir = $(KBUILD_OUTPUT)/kselftest/usr/include
+endif
+endif
+
+CFLAGS += -I$(khdr_dir)
+
+# Standalone run
+ifeq (0,$(MAKELEVEL))
+CC := $(CROSS_COMPILE)gcc
+RUNNER_SRC = test_arm64_signals.src_shell
+RUNNER = test_arm64_signals.sh
+INSTALL_PATH ?= install/
+
+all: $(RUNNER)
+
+$(RUNNER): $(PROGS)
+ cp $(RUNNER_SRC) $(RUNNER)
+ sed -i -e 's#PROGS=.*#PROGS="$(PROGS)"#' $@
+
+install: all
+ mkdir -p $(INSTALL_PATH)/testcases
+ cp $(PROGS) $(INSTALL_PATH)/testcases
+ cp $(RUNNER) $(INSTALL_PATH)/
+
+.PHONY clean:
+ rm -f $(PROGS)
+# KSFT run
+else
+# Generated binaries to be installed by top KSFT script
+TEST_GEN_PROGS := $(notdir $(PROGS))
+
+# Get Kernel headers installed and use them.
+KSFT_KHDR_INSTALL := 1
+
+# This include mk will also mangle the TEST_GEN_PROGS list
+# to account for any OUTPUT target-dirs optionally provided
+# by the toplevel makefile
+include ../../lib.mk
+
+$(TEST_GEN_PROGS): $(PROGS)
+ cp $(PROGS) $(OUTPUT)/
+
+clean:
+ $(CLEAN)
+ rm -f $(PROGS)
+endif
+
+# Common test-unit targets to build common-layout test-cases executables
+# Needs secondary expansion to properly include the testcase c-file in pre-reqs
+.SECONDEXPANSION:
+$(PROGS): test_signals.c test_signals_utils.c testcases/testcases.c $$@.c test_signals.h test_signals_utils.h testcases/testcases.h
+ @if [ ! -d $(khdr_dir) ]; then \
+ echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
+ echo "===> Are you sure Kernel Headers have been installed properly ?\n"; \
+ fi
+ $(CC) $(CFLAGS) $^ -o $@
diff --git a/tools/testing/selftests/arm64/signal/README b/tools/testing/selftests/arm64/signal/README
new file mode 100644
index 000000000000..53f005f7910a
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/README
@@ -0,0 +1,59 @@
+KSelfTest arm64/signal/
+=======================
+
+Signals Tests
++++++++++++++
+
+- Tests are built around a common main compilation unit: such shared main
+ enforces a standard sequence of operations needed to perform a single
+ signal-test (setup/trigger/run/result/cleanup)
+
+- The above mentioned ops are configurable on a test-by-test basis: each test
+ is described (and configured) using the descriptor signals.h::struct tdescr
+
+- Each signal testcase is compiled into its own executable: a separate
+ executable is used for each test since many tests complete successfully
+ by receiving some kind of fatal signal from the Kernel, so it's safer
+ to run each test unit in its own standalone process, so as to start each
+ test from a clean slate.
+
+- New tests can be simply defined in testcases/ dir providing a proper struct
+ tdescr overriding all the defaults we wish to change (as of now providing a
+ custom run method is mandatory though)
+
+- Signals' test-cases hereafter defined belong currently to two
+ principal families:
+
+ - 'mangle_' tests: a real signal (SIGUSR1) is raised and used as a trigger
+ and then the test case code messes-up with the sigframe ucontext_t from
+ inside the sighandler itself.
+
+ - 'fake_sigreturn_' tests: a brand new custom artificial sigframe structure
+ is placed on the stack and a sigreturn syscall is called to simulate a
+ real signal return. This kind of tests does not use a trigger usually and
+ they are just fired using some simple included assembly trampoline code.
+
+ - Most of these tests are successfully passing if the process gets killed by
+ some fatal signal: usually SIGSEGV or SIGBUS. Since while writing this
+ kind of tests it is extremely easy in fact to end-up injecting other
+ unrelated SEGV bugs in the testcases, it becomes extremely tricky to
+ be really sure that the tests are really addressing what they are meant
+ to address and they are not instead falling apart due to unplanned bugs
+ in the test code.
+ In order to alleviate the misery of the life of such test-developer, a few
+ helpers are provided:
+
+ - a couple of ASSERT_BAD/GOOD_CONTEXT() macros to easily parse a ucontext_t
+ and verify if it is indeed GOOD or BAD (depending on what we were
+ expecting), using the same logic/perspective as in the arm64 Kernel signals
+ routines.
+
+ - a sanity mechanism to be used in 'fake_sigreturn_'-alike tests: enabled by
+ default it takes care to verify that the test-execution had at least
+ successfully progressed up to the stage of triggering the fake sigreturn
+ call.
+
+ In both cases test results are expected in terms of:
+ - some fatal signal sent by the Kernel to the test process
+ or
+ - analyzing some final regs state
diff --git a/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
new file mode 100755
index 000000000000..163e941e2997
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_arm64_signals.src_shell
@@ -0,0 +1,55 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2019 ARM Limited
+
+ret=0
+keep_on_fail=0
+err_out="2> /dev/null"
+
+usage() {
+ echo "Usage: `basename $0` [-v] [-k]"
+ exit 1
+}
+
+# avoiding getopt to avoid compatibility issues on targets
+# with limited resources
+while [ $# -gt 0 ]
+do
+ case $1 in
+ "-k")
+ keep_on_fail=1
+ ;;
+ "-v")
+ err_out=
+ ;;
+ *)
+ usage
+ ;;
+ esac
+ shift
+done
+
+TPROGS=
+
+tot=$(echo $TPROGS | wc -w)
+
+# Tests are expected in testcases/ subdir inside the installation path
+workdir="`dirname $0 2>/dev/null`"
+[ -n $workdir ] && cd $workdir
+
+passed=0
+run=0
+for test in $TPROGS
+do
+ run=$((run + 1))
+ eval ./$test $err_out
+ if [ $? != 0 ]; then
+ [ $keep_on_fail = 0 ] && echo "===>>> FAILED:: $test <<<===" && ret=1 && break
+ else
+ passed=$((passed + 1))
+ fi
+done
+
+echo "==>> PASSED: $passed/$run on $tot available tests."
+
+exit $ret
diff --git a/tools/testing/selftests/arm64/signal/test_signals.c b/tools/testing/selftests/arm64/signal/test_signals.c
new file mode 100644
index 000000000000..3447d7011aec
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals.c
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <kselftest.h>
+
+#include "test_signals.h"
+#include "test_signals_utils.h"
+
+struct tdescr *current;
+extern struct tdescr tde;
+
+int main(int argc, char *argv[])
+{
+ current = &tde;
+
+ ksft_print_msg("%s :: %s - SIG_TRIG:%d SIG_OK:%d -- current:%p\n",
+ current->name, current->descr, current->sig_trig,
+ current->sig_ok, current);
+ if (test_setup(current)) {
+ if (test_run(current))
+ test_result(current);
+ test_cleanup(current);
+ }
+
+ return current->pass ? KSFT_PASS : KSFT_FAIL;
+}
diff --git a/tools/testing/selftests/arm64/signal/test_signals.h b/tools/testing/selftests/arm64/signal/test_signals.h
new file mode 100644
index 000000000000..85db3ac44b32
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#ifndef __TEST_SIGNALS_H__
+#define __TEST_SIGNALS_H__
+
+#include <assert.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <ucontext.h>
+#include <stdint.h>
+
+/*
+ * Using ARCH specific and sanitized Kernel headers installed by KSFT
+ * framework since we asked for it by setting flag KSFT_KHDR_INSTALL
+ * in our Makefile.
+ */
+#include <asm/ptrace.h>
+#include <asm/hwcap.h>
+
+/* pasted from include/linux/stringify.h */
+#define __stringify_1(x...) #x
+#define __stringify(x...) __stringify_1(x)
+
+/*
+ * Reads a sysreg using the, possibly provided, S3_ encoding in order to
+ * avoid inject any dependency on the used toolchain regarding possibly
+ * still unsupported ARMv8 extensions.
+ *
+ * Using a standard mnemonic here to indicate the specific sysreg (like SSBS)
+ * would introduce a compile-time dependency on possibly unsupported ARMv8
+ * Extensions: you could end-up failing to build the test depending on the
+ * available toolchain.
+ * This is undesirable since some tests, even if specifically targeted at some
+ * ARMv8 Extensions, can be plausibly run even on hardware lacking the above
+ * optional ARM features. (SSBS bit preservation is an example: Kernel handles
+ * it transparently not caring at all about the effective set of supported
+ * features).
+ * On the other side we will expect to observe different behaviours if the
+ * feature is supported or not: usually getting a SIGILL when trying to use
+ * unsupported features. For this reason we have anyway in place some
+ * preliminary run-time checks about the cpu effectively supported features.
+ *
+ * This helper macro is meant to be used for regs readable at EL0, BUT some
+ * EL1 sysregs are indeed readable too through MRS emulation Kernel-mechanism
+ * if the required reg is included in the supported encoding space:
+ *
+ * Documentation/arm64/cpu-feature-regsiters.txt
+ *
+ * "The infrastructure emulates only the following system register space:
+ * Op0=3, Op1=0, CRn=0, CRm=0,4,5,6,7
+ */
+#define get_regval(regname, out) \
+ asm volatile("mrs %0, " __stringify(regname) : "=r" (out) :: "memory")
+
+/* Regs encoding and masks naming copied in from sysreg.h */
+#define SYS_ID_AA64MMFR1_EL1 S3_0_C0_C7_1 /* MRS Emulated */
+#define SYS_ID_AA64MMFR2_EL1 S3_0_C0_C7_2 /* MRS Emulated */
+#define ID_AA64MMFR1_PAN_SHIFT 20
+#define ID_AA64MMFR2_UAO_SHIFT 4
+
+/* Local Helpers */
+#define IS_PAN_SUPPORTED(val) \
+ (!!((val) & (0xfUL << ID_AA64MMFR1_PAN_SHIFT)))
+#define IS_UAO_SUPPORTED(val) \
+ (!!((val) & (0xfUL << ID_AA64MMFR2_UAO_SHIFT)))
+
+#define S3_MRS_SSBS_SYSREG S3_3_C4_C2_6 /* EL0 supported */
+
+/*
+ * Feature flags used in tdescr.feats_required to specify
+ * any feature by the test
+ */
+enum {
+ FSSBS_BIT,
+ FPAN_BIT,
+ FUAO_BIT,
+ FMAX_END
+};
+
+#define FEAT_SSBS (1UL << FSSBS_BIT)
+#define FEAT_PAN (1UL << FPAN_BIT)
+#define FEAT_UAO (1UL << FUAO_BIT)
+
+/*
+ * A descriptor used to describe and configure a test case.
+ * Fields with a non-trivial meaning are described inline in the following.
+ */
+struct tdescr {
+ /* KEEP THIS FIELD FIRST for easier lookup from assembly */
+ void *token;
+ /* when disabled token based sanity checking is skipped in handler */
+ bool sanity_disabled;
+ /* just a name for the test-case; manadatory field */
+ char *name;
+ char *descr;
+ unsigned long feats_required;
+ /* bitmask of effectively supported feats: populated at run-time */
+ unsigned long feats_supported;
+ bool feats_ok;
+ bool initialized;
+ unsigned int minsigstksz;
+ /* signum used as a test trigger. Zero if no trigger-signal is used */
+ int sig_trig;
+ /*
+ * signum considered as a successful test completion.
+ * Zero when no signal is expected on success
+ */
+ int sig_ok;
+ /* signum expected on unsupported CPU features. */
+ int sig_unsupp;
+ /* a timeout in second for test completion */
+ unsigned int timeout;
+ bool triggered;
+ bool pass;
+ /* optional sa_flags for the installed handler */
+ int sa_flags;
+ ucontext_t saved_uc;
+
+ /* a setup function to be called before test starts */
+ int (*setup)(struct tdescr *td);
+ void (*cleanup)(struct tdescr *td);
+
+ /* an optional function to be used as a trigger for test starting */
+ int (*trigger)(struct tdescr *td);
+ /*
+ * the actual test-core: invoked differently depending on the
+ * presence of the trigger function above; this is mandatory
+ */
+ int (*run)(struct tdescr *td, siginfo_t *si, ucontext_t *uc);
+
+ /* an optional function for custom results' processing */
+ void (*check_result)(struct tdescr *td);
+
+ void *priv;
+};
+#endif
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.c b/tools/testing/selftests/arm64/signal/test_signals_utils.c
new file mode 100644
index 000000000000..ac0055f6340b
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.c
@@ -0,0 +1,261 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <sys/auxv.h>
+#include <linux/auxvec.h>
+#include <ucontext.h>
+
+#include "test_signals.h"
+#include "test_signals_utils.h"
+#include "testcases/testcases.h"
+
+extern struct tdescr *current;
+
+static char *feats_store[FMAX_END] = {
+ "SSBS",
+ "PAN",
+ "UAO"
+};
+
+#define MAX_FEATS_SZ 128
+static inline char *feats_to_string(unsigned long feats)
+{
+ static char feats_string[MAX_FEATS_SZ];
+
+ for (int i = 0; i < FMAX_END && feats_store[i][0]; i++) {
+ if (feats & 1UL << i)
+ snprintf(feats_string, MAX_FEATS_SZ - 1, "%s %s ",
+ feats_string, feats_store[i]);
+ }
+
+ return feats_string;
+}
+
+static void unblock_signal(int signum)
+{
+ sigset_t sset;
+
+ sigemptyset(&sset);
+ sigaddset(&sset, signum);
+ sigprocmask(SIG_UNBLOCK, &sset, NULL);
+}
+
+static void default_result(struct tdescr *td, bool force_exit)
+{
+ if (td->pass)
+ fprintf(stderr, "==>> completed. PASS(1)\n");
+ else
+ fprintf(stdout, "==>> completed. FAIL(0)\n");
+ if (force_exit)
+ exit(td->pass ? EXIT_SUCCESS : EXIT_FAILURE);
+}
+
+static inline bool are_feats_ok(struct tdescr *td)
+{
+ return td ? td->feats_required == td->feats_supported : 0;
+}
+
+static void default_handler(int signum, siginfo_t *si, void *uc)
+{
+ if (current->sig_trig && signum == current->sig_trig) {
+ fprintf(stderr, "Handling SIG_TRIG\n");
+ current->triggered = 1;
+ /* ->run was asserted NON-NULL in test_setup() already */
+ current->run(current, si, uc);
+ } else if (signum == SIGILL && !current->initialized) {
+ /*
+ * A SIGILL here while still not initialized means we failed
+ * even to asses the existence of features during init
+ */
+ fprintf(stdout,
+ "Got SIGILL test_init. Marking ALL features UNSUPPORTED.\n");
+ current->feats_supported = 0;
+ } else if (current->sig_ok && signum == current->sig_ok) {
+ /* it's a bug in the test code when this assert fail */
+ assert(!current->sig_trig || current->triggered);
+ fprintf(stderr,
+ "SIG_OK -- SP:%p si_addr@:0x%p si_code:%d token@:0x%p offset:%ld\n",
+ ((ucontext_t *)uc)->uc_mcontext.sp,
+ si->si_addr, si->si_code, current->token,
+ current->token - si->si_addr);
+ /*
+ * fake_sigreturn tests, which have sanity_enabled=1, set, at
+ * the very last time, the token field to the SP address used
+ * to place the fake sigframe: so token==0 means we never made
+ * it to the end, segfaulting well-before, and the test is
+ * possibly broken.
+ */
+ if (!current->sanity_disabled && !current->token) {
+ fprintf(stdout,
+ "current->token ZEROED...test is probably broken!\n");
+ assert(0);
+ }
+ /*
+ * Trying to narrow down the SEGV to the ones generated by
+ * Kernel itself via arm64_notify_segfault()
+ */
+ if (current->sig_ok == SIGSEGV && si->si_code != SEGV_ACCERR) {
+ fprintf(stdout,
+ "si_code != SEGV_ACCERR...test is probably broken!\n");
+ assert(0);
+ }
+ fprintf(stderr, "Handling SIG_OK\n");
+ current->pass = 1;
+ /*
+ * Some tests can lead to SEGV loops: in such a case we want
+ * to terminate immediately exiting straight away
+ */
+ default_result(current, 1);
+ } else {
+ if (signum == current->sig_unsupp && !are_feats_ok(current)) {
+ fprintf(stderr, "-- RX SIG_UNSUPP on unsupported feature...OK\n");
+ current->pass = 1;
+ } else if (signum == SIGALRM && current->timeout) {
+ fprintf(stderr, "-- Timeout !\n");
+ } else {
+ fprintf(stderr,
+ "-- RX UNEXPECTED SIGNAL: %d\n", signum);
+ }
+ default_result(current, 1);
+ }
+}
+
+static int default_setup(struct tdescr *td)
+{
+ struct sigaction sa;
+
+ sa.sa_sigaction = default_handler;
+ sa.sa_flags = SA_SIGINFO;
+ if (td->sa_flags)
+ sa.sa_flags |= td->sa_flags;
+ sigemptyset(&sa.sa_mask);
+ /* uncatchable signals naturally skipped ... */
+ for (int sig = 1; sig < 32; sig++)
+ sigaction(sig, &sa, NULL);
+ /*
+ * RT Signals default disposition is Term but they cannot be
+ * generated by the Kernel in response to our tests; so just catch
+ * them all and report them as UNEXPECTED signals.
+ */
+ for (int sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
+ sigaction(sig, &sa, NULL);
+
+ /* just in case...unblock explicitly all we need */
+ if (td->sig_trig)
+ unblock_signal(td->sig_trig);
+ if (td->sig_ok)
+ unblock_signal(td->sig_ok);
+ if (td->sig_unsupp)
+ unblock_signal(td->sig_unsupp);
+
+ if (td->timeout) {
+ unblock_signal(SIGALRM);
+ alarm(td->timeout);
+ }
+ fprintf(stderr, "Registered handlers for all signals.\n");
+
+ return 1;
+}
+
+static inline int default_trigger(struct tdescr *td)
+{
+ return !raise(td->sig_trig);
+}
+
+static int test_init(struct tdescr *td)
+{
+ td->minsigstksz = getauxval(AT_MINSIGSTKSZ);
+ if (!td->minsigstksz)
+ td->minsigstksz = MINSIGSTKSZ;
+ fprintf(stderr, "Detected MINSTKSIGSZ:%d\n", td->minsigstksz);
+
+ if (td->feats_required) {
+ bool feats_ok = false;
+ td->feats_supported = 0;
+ /*
+ * Checking for CPU required features using both the
+ * auxval and the arm64 MRS Emulation to read sysregs.
+ */
+ if (getauxval(AT_HWCAP) & HWCAP_CPUID) {
+ uint64_t val = 0;
+
+ if (td->feats_required & FEAT_SSBS) {
+ /* Uses HWCAP to check capability */
+ if (getauxval(AT_HWCAP) & HWCAP_SSBS)
+ td->feats_supported |= FEAT_SSBS;
+ }
+ if (td->feats_required & FEAT_PAN) {
+ /* Uses MRS emulation to check capability */
+ get_regval(SYS_ID_AA64MMFR1_EL1, val);
+ if (IS_PAN_SUPPORTED(val))
+ td->feats_supported |= FEAT_PAN;
+ }
+ if (td->feats_required & FEAT_UAO) {
+ /* Uses MRS emulation to check capability */
+ get_regval(SYS_ID_AA64MMFR2_EL1 , val);
+ if (IS_UAO_SUPPORTED(val))
+ td->feats_supported |= FEAT_UAO;
+ }
+ } else {
+ fprintf(stderr,
+ "HWCAP_CPUID NOT available. Mark ALL feats UNSUPPORTED.\n");
+ }
+ feats_ok = are_feats_ok(td);
+ fprintf(stderr,
+ "Required Features: [%s] %ssupported\n",
+ feats_ok ? feats_to_string(td->feats_supported) :
+ feats_to_string(td->feats_required ^ td->feats_supported),
+ !feats_ok ? "NOT " : "");
+ }
+
+ td->initialized = 1;
+ return 1;
+}
+
+int test_setup(struct tdescr *td)
+{
+ /* assert core invariants symptom of a rotten testcase */
+ assert(current);
+ assert(td);
+ assert(td->name);
+ assert(td->run);
+
+ if (!test_init(td))
+ return 0;
+
+ if (td->setup)
+ return td->setup(td);
+ else
+ return default_setup(td);
+}
+
+int test_run(struct tdescr *td)
+{
+ if (td->sig_trig) {
+ if (td->trigger)
+ return td->trigger(td);
+ else
+ return default_trigger(td);
+ } else {
+ return td->run(td, NULL, NULL);
+ }
+}
+
+void test_result(struct tdescr *td)
+{
+ if (td->check_result)
+ td->check_result(td);
+ default_result(td, 0);
+}
+
+void test_cleanup(struct tdescr *td)
+{
+ if (td->cleanup)
+ td->cleanup(td);
+}
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
new file mode 100644
index 000000000000..8658d1a7d4b9
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#ifndef __TEST_SIGNALS_UTILS_H__
+#define __TEST_SIGNALS_UTILS_H__
+
+#include "test_signals.h"
+
+int test_setup(struct tdescr *td);
+void test_cleanup(struct tdescr *td);
+int test_run(struct tdescr *td);
+void test_result(struct tdescr *td);
+#endif
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
new file mode 100644
index 000000000000..8651272e3cfc
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -0,0 +1 @@
+mangle_pstate_invalid_compat_toggle
diff --git a/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
new file mode 100644
index 000000000000..971193e7501b
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/mangle_pstate_invalid_compat_toggle.c
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+static int mangle_invalid_pstate_run(struct tdescr *td, siginfo_t *si,
+ ucontext_t *uc)
+{
+ ASSERT_GOOD_CONTEXT(uc);
+
+ /* This config should trigger a SIGSEGV by Kernel */
+ uc->uc_mcontext.pstate ^= PSR_MODE32_BIT;
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .sanity_disabled = true,
+ .name = "MANGLE_PSTATE_INVALID_STATE_TOGGLE",
+ .descr = "Mangling uc_mcontext with INVALID STATE_TOGGLE",
+ .sig_trig = SIGUSR1,
+ .sig_ok = SIGSEGV,
+ .run = mangle_invalid_pstate_run,
+};
diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.c b/tools/testing/selftests/arm64/signal/testcases/testcases.c
new file mode 100644
index 000000000000..a59785092e1f
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.c
@@ -0,0 +1,150 @@
+#include "testcases.h"
+
+struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
+ size_t resv_sz, size_t *offset)
+{
+ size_t offs = 0;
+ struct _aarch64_ctx *found = NULL;
+
+ if (!head || resv_sz < HDR_SZ)
+ return found;
+
+ do {
+ if (head->magic == magic) {
+ found = head;
+ break;
+ }
+ offs += head->size;
+ head = GET_RESV_NEXT_HEAD(head);
+ } while (offs < resv_sz - HDR_SZ);
+
+ if (offset)
+ *offset = offs;
+
+ return found;
+}
+
+bool validate_extra_context(struct extra_context *extra, char **err)
+{
+ struct _aarch64_ctx *term;
+
+ if (!extra || !err)
+ return false;
+
+ fprintf(stderr, "Validating EXTRA...\n");
+ term = GET_RESV_NEXT_HEAD(extra);
+ if (!term || term->magic || term->size) {
+ *err = "UN-Terminated EXTRA context";
+ return false;
+ }
+ if (extra->datap & 0x0fUL)
+ *err = "Extra DATAP misaligned";
+ else if (extra->size & 0x0fUL)
+ *err = "Extra SIZE misaligned";
+ else if (extra->datap != (uint64_t)term + sizeof(*term))
+ *err = "Extra DATAP misplaced (not contiguos)";
+ if (*err)
+ return false;
+
+ return true;
+}
+
+bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err)
+{
+ bool terminated = false;
+ size_t offs = 0;
+ int flags = 0;
+ struct extra_context *extra = NULL;
+ struct _aarch64_ctx *head =
+ (struct _aarch64_ctx *)uc->uc_mcontext.__reserved;
+
+ if (!err)
+ return false;
+ /* Walk till the end terminator verifying __reserved contents */
+ while (head && !terminated && offs < resv_sz) {
+ if ((uint64_t)head & 0x0fUL) {
+ *err = "Misaligned HEAD";
+ return false;
+ }
+
+ switch (head->magic) {
+ case 0:
+ if (head->size)
+ *err = "Bad size for MAGIC0";
+ else
+ terminated = true;
+ break;
+ case FPSIMD_MAGIC:
+ if (flags & FPSIMD_CTX)
+ *err = "Multiple FPSIMD_MAGIC";
+ else if (head->size !=
+ sizeof(struct fpsimd_context))
+ *err = "Bad size for fpsimd_context";
+ flags |= FPSIMD_CTX;
+ break;
+ case ESR_MAGIC:
+ if (head->size != sizeof(struct esr_context))
+ fprintf(stderr,
+ "Bad size for esr_context is not an error...just ignore.\n");
+ break;
+ case SVE_MAGIC:
+ if (flags & SVE_CTX)
+ *err = "Multiple SVE_MAGIC";
+ else if (head->size !=
+ sizeof(struct sve_context))
+ *err = "Bad size for sve_context";
+ flags |= SVE_CTX;
+ break;
+ case EXTRA_MAGIC:
+ if (flags & EXTRA_CTX)
+ *err = "Multiple EXTRA_MAGIC";
+ else if (head->size !=
+ sizeof(struct extra_context))
+ *err = "Bad size for extra_context";
+ flags |= EXTRA_CTX;
+ extra = (struct extra_context *)head;
+ break;
+ case KSFT_BAD_MAGIC:
+ /*
+ * This is a BAD magic header defined
+ * artificially by a testcase and surely
+ * unknown to the Kernel parse_user_sigframe().
+ * It MUST cause a Kernel induced SEGV
+ */
+ *err = "BAD MAGIC !";
+ break;
+ default:
+ /*
+ * A still unknown Magic: potentially freshly added
+ * to the Kernel code and still unknown to the
+ * tests.
+ */
+ fprintf(stdout,
+ "SKIP Unknown MAGIC: 0x%X - Is KSFT arm64/signal up to date ?\n",
+ head->magic);
+ break;
+ }
+
+ if (*err)
+ return false;
+
+ offs += head->size;
+ if (resv_sz - offs < sizeof(*head)) {
+ *err = "HEAD Overrun";
+ return false;
+ }
+
+ if (flags & EXTRA_CTX)
+ if (!validate_extra_context(extra, err))
+ return false;
+
+ head = GET_RESV_NEXT_HEAD(head);
+ }
+
+ if (terminated && !(flags & FPSIMD_CTX)) {
+ *err = "Missing FPSIMD";
+ return false;
+ }
+
+ return true;
+}
diff --git a/tools/testing/selftests/arm64/signal/testcases/testcases.h b/tools/testing/selftests/arm64/signal/testcases/testcases.h
new file mode 100644
index 000000000000..624717c71b1d
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/testcases.h
@@ -0,0 +1,83 @@
+#ifndef __TESTCASES_H__
+#define __TESTCASES_H__
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <ucontext.h>
+#include <assert.h>
+
+/* Architecture specific sigframe definitions */
+#include <asm/sigcontext.h>
+
+#define FPSIMD_CTX (1 << 0)
+#define SVE_CTX (1 << 1)
+#define EXTRA_CTX (1 << 2)
+
+#define KSFT_BAD_MAGIC 0xdeadbeef
+
+#define HDR_SZ \
+ sizeof(struct _aarch64_ctx)
+
+#define GET_SF_RESV_HEAD(sf) \
+ (struct _aarch64_ctx *)(&(sf).uc.uc_mcontext.__reserved)
+
+#define GET_SF_RESV_SIZE(sf) \
+ sizeof((sf).uc.uc_mcontext.__reserved)
+
+#define GET_UCP_RESV_SIZE(ucp) \
+ sizeof((ucp)->uc_mcontext.__reserved)
+
+#define ASSERT_BAD_CONTEXT(uc) do { \
+ char *err = NULL; \
+ assert(!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err));\
+ if (err) \
+ fprintf(stderr, \
+ "Using badly built context - ERR: %s\n", err); \
+} while(0)
+
+#define ASSERT_GOOD_CONTEXT(uc) do { \
+ char *err = NULL; \
+ if (!validate_reserved((uc), GET_UCP_RESV_SIZE((uc)), &err)) { \
+ if (err) \
+ fprintf(stderr, \
+ "Detected BAD context - ERR: %s\n", err);\
+ assert(0); \
+ } else { \
+ fprintf(stderr, "uc context validated.\n"); \
+ } \
+} while(0)
+
+/* head->size accounts both for payload and header _aarch64_ctx size ! */
+#define GET_RESV_NEXT_HEAD(h) \
+ (struct _aarch64_ctx *)((char *)(h) + (h)->size)
+
+struct fake_sigframe {
+ siginfo_t info;
+ ucontext_t uc;
+};
+
+
+bool validate_reserved(ucontext_t *uc, size_t resv_sz, char **err);
+
+bool validate_extra_context(struct extra_context *extra, char **err);
+
+struct _aarch64_ctx *get_header(struct _aarch64_ctx *head, uint32_t magic,
+ size_t resv_sz, size_t *offset);
+
+static inline struct _aarch64_ctx *get_terminator(struct _aarch64_ctx *head,
+ size_t resv_sz,
+ size_t *offset)
+{
+ return get_header(head, 0, resv_sz, offset);
+}
+
+static inline void write_terminator_record(struct _aarch64_ctx *tail)
+{
+ if (tail) {
+ tail->magic = 0;
+ tail->size = 0;
+ }
+}
+#endif
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 07/11] kselftest: arm64: fake_sigreturn_bad_size_for_magic0
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin
In-Reply-To: <20190802170300.20662-1-cristian.marussi@arm.com>
Added a simple fake_sigreturn testcase which builds a ucontext_t
with a badly sized magic0 header and place it onto the stack.
Expects a SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../arm64/signal/testcases/.gitignore | 1 +
.../fake_sigreturn_bad_size_for_magic0.c | 57 +++++++++++++++++++
2 files changed, 58 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 0ea6fdc3765c..cf2a73599818 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -5,3 +5,4 @@ mangle_pstate_invalid_mode_el2
mangle_pstate_invalid_mode_el3
mangle_pstate_ssbs_regs
fake_sigreturn_bad_magic
+fake_sigreturn_bad_size_for_magic0
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
new file mode 100644
index 000000000000..2f53c4740c85
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size_for_magic0.c
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+#define MIN_SZ_ALIGN 16
+
+static int fake_sigreturn_bad_size_for_magic0_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ size_t resv_sz, offset;
+ struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
+
+ /* just to fill the ucontext_t with something real */
+ if (!get_current_context(td, &sf.uc))
+ return 1;
+
+ resv_sz = GET_SF_RESV_SIZE(sf);
+ /*
+ * find the terminator, preserving existing headers
+ * and verify amount of spare room in __reserved area.
+ */
+ head = get_terminator(shead, resv_sz, &offset);
+ /*
+ * try stripping extra_context header when low on space:
+ * we need at least HDR_SZ + 16 space for the bad sized terminator.
+ */
+ if (head && resv_sz - offset < HDR_SZ + MIN_SZ_ALIGN) {
+ fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+ resv_sz - offset);
+ head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
+ }
+ /* just give up and timeout if still not enough space */
+ if (head && resv_sz - offset >= HDR_SZ + MIN_SZ_ALIGN) {
+ head->magic = 0;
+ head->size = MIN_SZ_ALIGN;
+
+ ASSERT_BAD_CONTEXT(&sf.uc);
+ fake_sigreturn(&sf, sizeof(sf), 16);
+ }
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_BAD_SIZE_FOR_MAGIC0",
+ .descr = "Triggers a fake sigreturn with a sigframe including a bad non-zero size magic0",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_bad_size_for_magic0_run,
+};
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 06/11] kselftest: arm64: fake_sigreturn_bad_magic
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin
In-Reply-To: <20190802170300.20662-1-cristian.marussi@arm.com>
Added a simple fake_sigreturn testcase which builds a ucontext_t
with a bad magic header and place it onto the stack.
Expects a SIGSEGV on test PASS.
This commit also introduces a common utility assembly function to
invoke a sigreturn using a fake provided sigframe.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
tools/testing/selftests/arm64/signal/Makefile | 2 +-
.../testing/selftests/arm64/signal/signals.S | 64 +++++++++++++++++++
.../arm64/signal/test_signals_utils.h | 1 +
.../arm64/signal/testcases/.gitignore | 1 +
.../testcases/fake_sigreturn_bad_magic.c | 63 ++++++++++++++++++
5 files changed, 130 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/selftests/arm64/signal/signals.S
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
diff --git a/tools/testing/selftests/arm64/signal/Makefile b/tools/testing/selftests/arm64/signal/Makefile
index 8c8d08be4b0d..b3dcf315b5a4 100644
--- a/tools/testing/selftests/arm64/signal/Makefile
+++ b/tools/testing/selftests/arm64/signal/Makefile
@@ -80,7 +80,7 @@ endif
# Common test-unit targets to build common-layout test-cases executables
# Needs secondary expansion to properly include the testcase c-file in pre-reqs
.SECONDEXPANSION:
-$(PROGS): test_signals.c test_signals_utils.c testcases/testcases.c $$@.c test_signals.h test_signals_utils.h testcases/testcases.h
+$(PROGS): test_signals.c test_signals_utils.c testcases/testcases.c signals.S $$@.c test_signals.h test_signals_utils.h testcases/testcases.h
@if [ ! -d $(khdr_dir) ]; then \
echo -n "\n!!! WARNING: $(khdr_dir) NOT FOUND."; \
echo "===> Are you sure Kernel Headers have been installed properly ?\n"; \
diff --git a/tools/testing/selftests/arm64/signal/signals.S b/tools/testing/selftests/arm64/signal/signals.S
new file mode 100644
index 000000000000..6262b877400b
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/signals.S
@@ -0,0 +1,64 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ * Copyright (C) 2019 ARM Limited
+ */
+
+#include <asm/unistd.h>
+
+.section ".rodata", "a"
+call_fmt:
+ .asciz "Calling sigreturn with fake sigframe sized:%zd at calculated SP @%08lX\n"
+
+.text
+
+.globl fake_sigreturn
+
+/* fake_sigreturn x0:&sigframe, x1:sigframe_size, x2:alignment_SP */
+fake_sigreturn:
+ mov x20, x0
+ mov x21, x1
+ mov x22, x2
+ mov x23, sp
+
+ /* create space on the stack for fake sigframe..."x22"-aligned */
+ mov x0, #0
+ add x0, x21, x22
+ sub x22, x22, #1
+ bic x0, x0, x22
+ sub x23, x23, x0
+
+ ldr x0, =call_fmt
+ mov x1, x21
+ mov x2, x23
+ bl printf
+
+ mov sp, x23
+
+ /* now fill it with the provided content... */
+ mov x0, sp
+ mov x1, x20
+ mov x2, x21
+ bl memcpy
+
+ /*
+ * Here saving a last minute SP to current->token acts as a marker:
+ * if we got here, we are successfully faking a sigreturn; in other
+ * words we are sure no bad fatal signal has been raised till now
+ * for unrelated reasons, so we should consider the possibl observed
+ * fatal signal like SEGV coming from Kernel restore_sigframe() and
+ * triggered as expected from our test-case.
+ * For simplicity this assumes that current field 'token' is laid out
+ * as first in struct tdescr
+ */
+ ldr x0, current
+ str x23, [x0]
+ /* SP is already pointing back to the just built fake sigframe here */
+ mov x8, #__NR_rt_sigreturn
+ svc #0
+
+ /*
+ * Above sigreturn should not return...looping here leads to a timeout
+ * and ensure proper and clean test failure, instead of jumping around
+ * on a potentially corrupted stack.
+ */
+ b .
diff --git a/tools/testing/selftests/arm64/signal/test_signals_utils.h b/tools/testing/selftests/arm64/signal/test_signals_utils.h
index ce35be8ebc8e..2a71da7e6695 100644
--- a/tools/testing/selftests/arm64/signal/test_signals_utils.h
+++ b/tools/testing/selftests/arm64/signal/test_signals_utils.h
@@ -12,4 +12,5 @@ int test_run(struct tdescr *td);
void test_result(struct tdescr *td);
bool get_current_context(struct tdescr *td, ucontext_t *dest_uc);
+int fake_sigreturn(void *sigframe, size_t sz, int alignment);
#endif
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index a48a118b1a1a..0ea6fdc3765c 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -4,3 +4,4 @@ mangle_pstate_invalid_mode_el1
mangle_pstate_invalid_mode_el2
mangle_pstate_invalid_mode_el3
mangle_pstate_ssbs_regs
+fake_sigreturn_bad_magic
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
new file mode 100644
index 000000000000..b4c063e02a7a
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_magic.c
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_bad_magic_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ size_t resv_sz, offset;
+ struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
+
+ /* just to fill the ucontext_t with something real */
+ if (!get_current_context(td, &sf.uc))
+ return 1;
+
+ resv_sz = GET_SF_RESV_SIZE(sf);
+ /*
+ * find the terminator, preserving existing headers
+ * and verify amount of spare room in __reserved area.
+ */
+ head = get_terminator(shead, resv_sz, &offset);
+ /*
+ * try stripping extra_context header when low on space:
+ * we need at least 2*HDR_SZ space ... one for the KSFT_BAD_MAGIC
+ * and the other for the usual terminator.
+ */
+ if (head && resv_sz - offset < HDR_SZ * 2) {
+ fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+ resv_sz - offset);
+ head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
+ }
+ /* just give up and timeout if still not enough space */
+ if (head && resv_sz - offset >= HDR_SZ) {
+ fprintf(stderr, "Mangling template header. Spare space:%zd\n",
+ resv_sz - offset);
+ /*
+ * use a well known NON existent bad magic...something
+ * we should pretty sure won't be ever defined in Kernel
+ */
+ head->magic = KSFT_BAD_MAGIC;
+ head->size = HDR_SZ;
+ write_terminator_record(GET_RESV_NEXT_HEAD(head));
+
+ ASSERT_BAD_CONTEXT(&sf.uc);
+ fake_sigreturn(&sf, sizeof(sf), 16);
+ }
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_BAD_MAGIC",
+ .descr = "Triggers a fake sigreturn with a sigframe including a bad non-existent magic",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_bad_magic_run,
+};
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 08/11] kselftest: arm64: fake_sigreturn_missing_fpsimd
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin
In-Reply-To: <20190802170300.20662-1-cristian.marussi@arm.com>
Added a simple fake_sigreturn testcase which builds a ucontext_t
without the required fpsimd_context and place it onto the stack.
Expects a SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../arm64/signal/testcases/.gitignore | 1 +
.../testcases/fake_sigreturn_missing_fpsimd.c | 44 +++++++++++++++++++
2 files changed, 45 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index cf2a73599818..17d1c5e73319 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -6,3 +6,4 @@ mangle_pstate_invalid_mode_el3
mangle_pstate_ssbs_regs
fake_sigreturn_bad_magic
fake_sigreturn_bad_size_for_magic0
+fake_sigreturn_missing_fpsimd
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
new file mode 100644
index 000000000000..b8dd57ce6844
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_missing_fpsimd.c
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_missing_fpsimd_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ size_t resv_sz, offset;
+ struct _aarch64_ctx *head = GET_SF_RESV_HEAD(sf);
+
+ /* just to fill the ucontext_t with something real */
+ if (!get_current_context(td, &sf.uc))
+ return 1;
+
+ resv_sz = GET_SF_RESV_SIZE(sf);
+ head = get_header(head, FPSIMD_MAGIC, resv_sz, &offset);
+ /* just give up and timeout if still not enough space */
+ if (head && resv_sz - offset >= HDR_SZ) {
+ fprintf(stderr, "Mangling template header. Spare space:%zd\n",
+ resv_sz - offset);
+ /* Just overwrite fpsmid_context */
+ write_terminator_record(head);
+
+ ASSERT_BAD_CONTEXT(&sf.uc);
+ fake_sigreturn(&sf, sizeof(sf), 16);
+ }
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_MISSING_FPSIMD",
+ .descr = "Triggers a fake sigreturn with a sigframe missing the mandatory fpsimd_context",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_missing_fpsimd_run,
+};
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 09/11] kselftest: arm64: fake_sigreturn_duplicated_fpsimd
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin
In-Reply-To: <20190802170300.20662-1-cristian.marussi@arm.com>
Added a simple fake_sigreturn testcase which builds a ucontext_t
with an anomalous additional fpsimd_context and place it onto the stack.
Expects a SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../arm64/signal/testcases/.gitignore | 1 +
.../fake_sigreturn_duplicated_fpsimd.c | 62 +++++++++++++++++++
2 files changed, 63 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 17d1c5e73319..94f9baaf638c 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -7,3 +7,4 @@ mangle_pstate_ssbs_regs
fake_sigreturn_bad_magic
fake_sigreturn_bad_size_for_magic0
fake_sigreturn_missing_fpsimd
+fake_sigreturn_duplicated_fpsimd
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
new file mode 100644
index 000000000000..09af7a0f8776
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_duplicated_fpsimd.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_duplicated_fpsimd_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ size_t resv_sz, offset;
+ struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
+
+ /* just to fill the ucontext_t with something real */
+ if (!get_current_context(td, &sf.uc))
+ return 1;
+
+ resv_sz = GET_SF_RESV_SIZE(sf);
+ /*
+ * find the terminator, preserving existing headers
+ * and verify amount of spare room in __reserved area.
+ */
+ head = get_terminator(shead, resv_sz, &offset);
+ /*
+ * try stripping extra_context header when low on space:
+ * we need at least space for one additional fpsimd_context
+ */
+ if (head && resv_sz - offset < sizeof(struct fpsimd_context)) {
+ fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+ resv_sz - offset);
+ head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
+ }
+
+ /* just give up and timeout if still not enough space */
+ if (head &&
+ resv_sz - offset >= sizeof(struct fpsimd_context) + HDR_SZ) {
+ fprintf(stderr, "Mangling template header. Spare space:%zd\n",
+ resv_sz - offset);
+ /* Add a spurios fpsimd_context */
+ head->magic = FPSIMD_MAGIC;
+ head->size = sizeof(struct fpsimd_context);
+ /* and terminate */
+ write_terminator_record(GET_RESV_NEXT_HEAD(head));
+
+ ASSERT_BAD_CONTEXT(&sf.uc);
+ fake_sigreturn(&sf, sizeof(sf), 16);
+ }
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_DUPLICATED_FPSIMD",
+ .descr = "Triggers a fake sigreturn with a sigframe including two fpsimd_context",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_duplicated_fpsimd_run,
+};
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 10/11] kselftest: arm64: fake_sigreturn_bad_size
From: Cristian Marussi @ 2019-08-02 17:02 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin
In-Reply-To: <20190802170300.20662-1-cristian.marussi@arm.com>
Added a simple fake_sigreturn testcase which builds a ucontext_t
with a badly sized header that causes a overrun in the __reserved
area and place it onto the stack. Expects a SIGSEGV on test PASS.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
.../arm64/signal/testcases/.gitignore | 1 +
.../testcases/fake_sigreturn_bad_size.c | 85 +++++++++++++++++++
2 files changed, 86 insertions(+)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
diff --git a/tools/testing/selftests/arm64/signal/testcases/.gitignore b/tools/testing/selftests/arm64/signal/testcases/.gitignore
index 94f9baaf638c..3408e0f5ba98 100644
--- a/tools/testing/selftests/arm64/signal/testcases/.gitignore
+++ b/tools/testing/selftests/arm64/signal/testcases/.gitignore
@@ -8,3 +8,4 @@ fake_sigreturn_bad_magic
fake_sigreturn_bad_size_for_magic0
fake_sigreturn_missing_fpsimd
fake_sigreturn_duplicated_fpsimd
+fake_sigreturn_bad_size
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
new file mode 100644
index 000000000000..1467fb534d8b
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_bad_size.c
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+#define MIN_SZ_ALIGN 16
+
+static int fake_sigreturn_bad_size_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ size_t resv_sz, need_sz, offset;
+ struct _aarch64_ctx *shead = GET_SF_RESV_HEAD(sf), *head;
+
+ /* just to fill the ucontext_t with something real */
+ if (!get_current_context(td, &sf.uc))
+ return 1;
+
+ resv_sz = GET_SF_RESV_SIZE(sf);
+ /*
+ * find the terminator, preserving existing headers
+ * and verify amount of spare room in __reserved area.
+ */
+ head = get_terminator(shead, resv_sz, &offset);
+ /*
+ * try stripping extra_context header when low on space:
+ * we need at least for the bad sized esr_context.
+ */
+ need_sz = HDR_SZ + sizeof(struct esr_context);
+ if (head && resv_sz - offset < need_sz) {
+ fprintf(stderr, "Low on space:%zd. Discarding extra_context.\n",
+ resv_sz - offset);
+ head = get_header(shead, EXTRA_MAGIC, resv_sz, &offset);
+ }
+ /* just give up and timeout if still not enough space */
+ if (head && resv_sz - offset >= need_sz) {
+ fprintf(stderr, "Mangling template header. Spare space:%zd\n",
+ resv_sz - offset);
+ /*
+ * Use an esr_context to build a fake header with a
+ * size greater then the free __reserved area minus HDR_SZ;
+ * using ESR_MAGIC here since it is not checked for size nor
+ * is limited to one instance.
+ *
+ * At first inject an additional normal esr_context
+ */
+ head->magic = ESR_MAGIC;
+ head->size = sizeof(struct esr_context);
+ /* and terminate properly */
+ write_terminator_record(GET_RESV_NEXT_HEAD(head));
+ ASSERT_GOOD_CONTEXT(&sf.uc);
+
+ /*
+ * now mess with fake esr_context size: leaving less space than
+ * neededwhile keeping size value 16-aligned
+ *
+ * It must trigger a SEGV from Kernel on:
+ *
+ * resv_sz - offset < sizeof(*head)
+ */
+ /* at first set the maximum good 16-aligned size */
+ head->size = (resv_sz - offset - need_sz + MIN_SZ_ALIGN) & ~0xfUL;
+ /* plus a bit more of 16-aligned sized stuff */
+ head->size += MIN_SZ_ALIGN;
+ /* and terminate properly */
+ write_terminator_record(GET_RESV_NEXT_HEAD(head));
+ ASSERT_BAD_CONTEXT(&sf.uc);
+ fake_sigreturn(&sf, sizeof(sf), 16);
+ }
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_BAD_SIZE",
+ .descr = "Triggers a fake sigreturn with a sigframe including a badly sized header which overruns the __reserved area",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_bad_size_run,
+};
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* [PATCH v3 11/11] kselftest: arm64: fake_sigreturn_misaligned_sp
From: Cristian Marussi @ 2019-08-02 17:03 UTC (permalink / raw)
To: linux-kselftest, linux-arm-kernel, shuah; +Cc: andreyknvl, dave.martin
In-Reply-To: <20190802170300.20662-1-cristian.marussi@arm.com>
Added a simple fake_sigreturn testcase which places a valid
sigframe on a non-16 bytes aligned SP.
fake_sigretrun() helper function has been patched accordingly
to support placing a sigframe on a non-16 bytes aligned address.
Expects a SIGSEGV on test PASS.
Adds also a test TODO lists holding some further test ideas.
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
---
Re-added this text after fixing the forced misaglinment procedure in
fake_sigreturn() itself: require a ZERO alignment and you'll get
your sigframe placed on a misaligned SP (2-bytes off the 16-align)
---
.../testing/selftests/arm64/signal/signals.S | 21 +++++++++----
.../arm64/signal/testcases/TODO.readme | 8 +++++
.../testcases/fake_sigreturn_misaligned_sp.c | 30 +++++++++++++++++++
3 files changed, 53 insertions(+), 6 deletions(-)
create mode 100644 tools/testing/selftests/arm64/signal/testcases/TODO.readme
create mode 100644 tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
diff --git a/tools/testing/selftests/arm64/signal/signals.S b/tools/testing/selftests/arm64/signal/signals.S
index 6262b877400b..2099871176ed 100644
--- a/tools/testing/selftests/arm64/signal/signals.S
+++ b/tools/testing/selftests/arm64/signal/signals.S
@@ -13,19 +13,28 @@ call_fmt:
.globl fake_sigreturn
-/* fake_sigreturn x0:&sigframe, x1:sigframe_size, x2:alignment_SP */
+/* fake_sigreturn x0:&sigframe, x1:sigframe_sz, x2:align */
fake_sigreturn:
- mov x20, x0
- mov x21, x1
- mov x22, x2
- mov x23, sp
- /* create space on the stack for fake sigframe..."x22"-aligned */
+ /* Save args and decide which aligment to enforce */
+ mov x23, sp
+ mov x20, x0
+ mov x21, x1
+ /* x22 and x24 used for forcing alignment or misalignment */
+ mov x22, x2
+ mov x24, #0
+ cbnz x22, 1f
+ mov x22, #16
+ mov x24, #2
+
+1: /* create space on the stack for fake sigframe..."x22"-aligned */
mov x0, #0
add x0, x21, x22
sub x22, x22, #1
bic x0, x0, x22
sub x23, x23, x0
+ /* force misaligned by x24 bytes if required alignment was zero */
+ add x23, x23, x24
ldr x0, =call_fmt
mov x1, x21
diff --git a/tools/testing/selftests/arm64/signal/testcases/TODO.readme b/tools/testing/selftests/arm64/signal/testcases/TODO.readme
new file mode 100644
index 000000000000..5c949492e7ab
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/TODO.readme
@@ -0,0 +1,8 @@
+Some more possible ideas for signals tests:
+
+- fake_sigreturn_unmapped_sp
+- fake_sigreturn_kernelspace_sp
+- fake_sigreturn_sve_bad_extra_context
+- mangle_sve_invalid_extra_context
+- mangle_pstate_invalid_el for H modes (+ macroization ?)
+- fake_sigreturn_overflow_reserved
diff --git a/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
new file mode 100644
index 000000000000..3ee8c500c7d1
--- /dev/null
+++ b/tools/testing/selftests/arm64/signal/testcases/fake_sigreturn_misaligned_sp.c
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2019 ARM Limited */
+
+#include <ucontext.h>
+
+#include "test_signals_utils.h"
+#include "testcases.h"
+
+struct fake_sigframe sf;
+
+static int fake_sigreturn_misaligned_run(struct tdescr *td,
+ siginfo_t *si, ucontext_t *uc)
+{
+ /* just to fill the ucontext_t with something real */
+ if (!get_current_context(td, &sf.uc))
+ return 1;
+
+ /* Forcing sigframe on misaligned (=!16) SP */
+ fake_sigreturn(&sf, sizeof(sf), 0);
+
+ return 1;
+}
+
+struct tdescr tde = {
+ .name = "FAKE_SIGRETURN_MISALIGNED_SP",
+ .descr = "Triggers a fake sigreturn with a misaligned sigframe on SP",
+ .sig_ok = SIGSEGV,
+ .timeout = 3,
+ .run = fake_sigreturn_misaligned_run,
+};
--
2.17.1
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply related
* Re: [PATCH 3/8] of/fdt: add function to get the SoC wide DMA addressable memory size
From: Rob Herring @ 2019-08-02 17:17 UTC (permalink / raw)
To: Nicolas Saenz Julienne
Cc: phill, devicetree,
moderated list:BROADCOM BCM2835 ARM ARCHITECTURE,
Florian Fainelli, Frank Rowand, Eric Anholt, Marc Zyngier,
Catalin Marinas, Will Deacon, linux-kernel@vger.kernel.org,
linux-mm, Linux IOMMU, Matthias Brugger, wahrenst, Andrew Morton,
Robin Murphy, Christoph Hellwig,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
Marek Szyprowski
In-Reply-To: <20190731154752.16557-4-nsaenzjulienne@suse.de>
On Wed, Jul 31, 2019 at 9:48 AM Nicolas Saenz Julienne
<nsaenzjulienne@suse.de> wrote:
>
> Some SoCs might have multiple interconnects each with their own DMA
> addressing limitations. This function parses the 'dma-ranges' on each of
> them and tries to guess the maximum SoC wide DMA addressable memory
> size.
>
> This is specially useful for arch code in order to properly setup CMA
> and memory zones.
We already have a way to setup CMA in reserved-memory, so why is this
needed for that?
I have doubts this can really be generic...
>
> Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
> ---
>
> drivers/of/fdt.c | 72 ++++++++++++++++++++++++++++++++++++++++++
> include/linux/of_fdt.h | 2 ++
> 2 files changed, 74 insertions(+)
>
> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
> index 9cdf14b9aaab..f2444c61a136 100644
> --- a/drivers/of/fdt.c
> +++ b/drivers/of/fdt.c
> @@ -953,6 +953,78 @@ int __init early_init_dt_scan_chosen_stdout(void)
> }
> #endif
>
> +/**
> + * early_init_dt_dma_zone_size - Look at all 'dma-ranges' and provide the
> + * maximum common dmable memory size.
> + *
> + * Some devices might have multiple interconnects each with their own DMA
> + * addressing limitations. For example the Raspberry Pi 4 has the following:
> + *
> + * soc {
> + * dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>;
> + * [...]
> + * }
> + *
> + * v3dbus {
> + * dma-ranges = <0x00000000 0x0 0x00000000 0x3c000000>;
> + * [...]
> + * }
> + *
> + * scb {
> + * dma-ranges = <0x0 0x00000000 0x0 0x00000000 0xfc000000>;
> + * [...]
> + * }
> + *
> + * Here the area addressable by all devices is [0x00000000-0x3bffffff]. Hence
> + * the function will write in 'data' a size of 0x3c000000.
> + *
> + * Note that the implementation assumes all interconnects have the same physical
> + * memory view and that the mapping always start at the beginning of RAM.
Not really a valid assumption for general code.
> + */
> +int __init early_init_dt_dma_zone_size(unsigned long node, const char *uname,
> + int depth, void *data)
Don't use the old fdt scanning interface with depth/data. It's not
really needed now because you can just use libfdt calls.
> +{
> + const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
> + u64 phys_addr, dma_addr, size;
> + u64 *dma_zone_size = data;
> + int dma_addr_cells;
> + const __be32 *reg;
> + const void *prop;
> + int len;
> +
> + if (depth == 0)
> + *dma_zone_size = 0;
> +
> + /*
> + * We avoid pci host controllers as they have their own way of using
> + * 'dma-ranges'.
> + */
> + if (type && !strcmp(type, "pci"))
> + return 0;
> +
> + reg = of_get_flat_dt_prop(node, "dma-ranges", &len);
> + if (!reg)
> + return 0;
> +
> + prop = of_get_flat_dt_prop(node, "#address-cells", NULL);
> + if (prop)
> + dma_addr_cells = be32_to_cpup(prop);
> + else
> + dma_addr_cells = 1; /* arm64's default addr_cell size */
Relying on the defaults has been a dtc error longer than arm64 has
existed. If they are missing, just bail.
> +
> + if (len < (dma_addr_cells + dt_root_addr_cells + dt_root_size_cells))
> + return 0;
> +
> + dma_addr = dt_mem_next_cell(dma_addr_cells, ®);
> + phys_addr = dt_mem_next_cell(dt_root_addr_cells, ®);
> + size = dt_mem_next_cell(dt_root_size_cells, ®);
> +
> + if (!*dma_zone_size || *dma_zone_size > size)
> + *dma_zone_size = size;
> +
> + return 0;
> +}
It's possible to have multiple levels of nodes and dma-ranges. You
need to handle that case too.
Doing that and handling differing address translations will be
complicated. IMO, I'd just do:
if (of_fdt_machine_is_compatible(blob, "brcm,bcm2711"))
dma_zone_size = XX;
2 lines of code is much easier to maintain than 10s of incomplete code
and is clearer who needs this. Maybe if we have dozens of SoCs with
this problem we should start parsing dma-ranges.
Rob
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [GIT PULL] arm64 fixes for 5.3-rc3
From: Catalin Marinas @ 2019-08-02 17:17 UTC (permalink / raw)
To: Linus Torvalds; +Cc: will, linux-kernel, linux-arm-kernel
Hi Linus,
Please pull the arm64 fixes below. Thanks.
The following changes since commit 609488bc979f99f805f34e9a32c1e3b71179d10b:
Linux 5.3-rc2 (2019-07-28 12:47:02 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux tags/arm64-fixes
for you to fetch changes up to d8bb6718c4db9bcd075dde7ff55d46091ccfae15:
arm64: Make debug exception handlers visible from RCU (2019-08-02 11:56:01 +0100)
----------------------------------------------------------------
arm64 fixes:
- Update the compat layer to allow single-byte watchpoints on all
addresses (similar to the native support)
- arm_pmu: fix the restoration of the counters on the
CPU_PM_ENTER_FAILED path
- Fix build regression with vDSO and Makefile not stripping
CROSS_COMPILE_COMPAT
- Fix the CTR_EL0 (cache type register) sanitisation on heterogeneous
machines (e.g. big.LITTLE)
- Fix the interrupt controller priority mask value when pseudo-NMIs are
enabled
- arm64 kprobes fixes: recovering of the PSTATE.D flag in the
single-step exception handler, NOKPROBE annotations for unwind_frame()
and walk_stackframe(), remove unneeded rcu_read_lock/unlock from debug
handlers
- Several gcc fall-through warnings
- Unused variable warnings
----------------------------------------------------------------
Anders Roxell (2):
arm64: smp: Mark expected switch fall-through
arm64: module: Mark expected switch fall-through
Julien Thierry (1):
arm64: Lower priority mask for GIC_PRIO_IRQON
Masami Hiramatsu (4):
arm64: unwind: Prohibit probing on return_address()
arm64: Remove unneeded rcu_read_lock from debug handlers
arm64: kprobes: Recover pstate.D in single-step exception handler
arm64: Make debug exception handlers visible from RCU
Qian Cai (3):
arm64/efi: fix variable 'si' set but not used
arm64/mm: fix variable 'pud' set but not used
arm64/mm: fix variable 'tag' set but not used
Vincenzo Frascino (1):
arm64: vdso: Fix Makefile regression
Will Deacon (4):
arm64: compat: Allow single-byte watchpoints on all addresses
drivers/perf: arm_pmu: Fix failure path in PM notifier
arm64: hw_breakpoint: Fix warnings about implicit fallthrough
arm64: cpufeature: Fix feature comparison for CTR_EL0.{CWG,ERG}
arch/arm64/Makefile | 2 +-
arch/arm64/include/asm/arch_gicv3.h | 6 ++++
arch/arm64/include/asm/cpufeature.h | 7 +++--
arch/arm64/include/asm/daifflags.h | 2 ++
arch/arm64/include/asm/efi.h | 6 +++-
arch/arm64/include/asm/memory.h | 10 +++++--
arch/arm64/include/asm/pgtable.h | 4 +--
arch/arm64/include/asm/ptrace.h | 2 +-
arch/arm64/kernel/cpufeature.c | 8 ++++--
arch/arm64/kernel/debug-monitors.c | 14 +++++----
arch/arm64/kernel/hw_breakpoint.c | 11 +++++--
arch/arm64/kernel/module.c | 4 +++
arch/arm64/kernel/probes/kprobes.c | 40 ++++----------------------
arch/arm64/kernel/return_address.c | 3 ++
arch/arm64/kernel/smp.c | 2 +-
arch/arm64/kernel/stacktrace.c | 3 ++
arch/arm64/mm/fault.c | 57 +++++++++++++++++++++++++++++++------
drivers/perf/arm_pmu.c | 2 +-
18 files changed, 117 insertions(+), 66 deletions(-)
--
Catalin
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [RFC PATCH] ARM: UNWINDER_FRAME_POINTER implementation for Clang
From: Nathan Huckleberry @ 2019-08-02 17:27 UTC (permalink / raw)
To: Robin Murphy
Cc: clang-built-linux, Tri Vo, linux, linux-arm-kernel, linux-kernel
In-Reply-To: <01222982-4206-9925-0482-639a79384451@arm.com>
You're right. Would pushing an extra register be an adequate fix?
On Fri, Aug 2, 2019 at 7:24 AM Robin Murphy <robin.murphy@arm.com> wrote:
>
> On 02/08/2019 00:10, Nathan Huckleberry wrote:
> > The stackframe setup when compiled with clang is different.
> > Since the stack unwinder expects the gcc stackframe setup it
> > fails to print backtraces. This patch adds support for the
> > clang stackframe setup.
> >
> > Cc: clang-built-linux@googlegroups.com
> > Suggested-by: Tri Vo <trong@google.com>
> > Signed-off-by: Nathan Huckleberry <nhuck@google.com>
> > ---
> > arch/arm/Kconfig.debug | 4 +-
> > arch/arm/Makefile | 2 +-
> > arch/arm/lib/backtrace.S | 134 ++++++++++++++++++++++++++++++++++++---
> > 3 files changed, 128 insertions(+), 12 deletions(-)
> >
> > diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
> > index 85710e078afb..92fca7463e21 100644
> > --- a/arch/arm/Kconfig.debug
> > +++ b/arch/arm/Kconfig.debug
> > @@ -56,7 +56,7 @@ choice
> >
> > config UNWINDER_FRAME_POINTER
> > bool "Frame pointer unwinder"
> > - depends on !THUMB2_KERNEL && !CC_IS_CLANG
> > + depends on !THUMB2_KERNEL
> > select ARCH_WANT_FRAME_POINTERS
> > select FRAME_POINTER
> > help
> > @@ -1872,7 +1872,7 @@ config DEBUG_UNCOMPRESS
> > When this option is set, the selected DEBUG_LL output method
> > will be re-used for normal decompressor output on multiplatform
> > kernels.
> > -
> > +
> >
> > config UNCOMPRESS_INCLUDE
> > string
> > diff --git a/arch/arm/Makefile b/arch/arm/Makefile
> > index c3624ca6c0bc..a593d9c4e18a 100644
> > --- a/arch/arm/Makefile
> > +++ b/arch/arm/Makefile
> > @@ -36,7 +36,7 @@ KBUILD_CFLAGS += $(call cc-option,-mno-unaligned-access)
> > endif
> >
> > ifeq ($(CONFIG_FRAME_POINTER),y)
> > -KBUILD_CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog
> > +KBUILD_CFLAGS +=-fno-omit-frame-pointer $(call cc-option,-mapcs,) $(call cc-option,-mno-sched-prolog,)
> > endif
> >
> > ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
> > diff --git a/arch/arm/lib/backtrace.S b/arch/arm/lib/backtrace.S
> > index 1d5210eb4776..fd64eec9f6ae 100644
> > --- a/arch/arm/lib/backtrace.S
> > +++ b/arch/arm/lib/backtrace.S
> > @@ -14,10 +14,7 @@
> > @ fp is 0 or stack frame
> >
> > #define frame r4
> > -#define sv_fp r5
> > -#define sv_pc r6
> > #define mask r7
> > -#define offset r8
> >
> > ENTRY(c_backtrace)
> >
> > @@ -25,7 +22,8 @@ ENTRY(c_backtrace)
> > ret lr
> > ENDPROC(c_backtrace)
> > #else
> > - stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location...
> > + stmfd sp!, {r4 - r8, fp, lr} @ Save an extra register
>
> Note that the Procedure Call Standard for EABI requires that SP be
> 8-byte-aligned at a public interface. Pushing an odd number of registers
> here looks like it will make the subsequent calls to dump_backtrace_*
> and printk violate that condition.
>
> Robin.
>
> > + @ so we have a location..
> > movs frame, r0 @ if frame pointer is zero
> > beq no_frame @ we have no stack frames
> >
> > @@ -35,11 +33,119 @@ ENDPROC(c_backtrace)
> > THUMB( orreq mask, #0x03 )
> > movne mask, #0 @ mask for 32-bit
> >
> > -1: stmfd sp!, {pc} @ calculate offset of PC stored
> > - ldr r0, [sp], #4 @ by stmfd for this CPU
> > - adr r1, 1b
> > - sub offset, r0, r1
> >
> > +#if defined(CONFIG_CC_IS_CLANG)
> > +/*
> > + * Clang does not store pc or sp in function prologues
> > + * so we don't know exactly where the function
> > + * starts.
> > + * We can treat the current frame's lr as the saved pc and the
> > + * preceding frame's lr as the lr, but we can't
> > + * trace the most recent call.
> > + * Inserting a false stack frame allows us to reference the
> > + * function called last in the stacktrace.
> > + * If the call instruction was a bl we can look at the callers
> > + * branch instruction to calculate the saved pc.
> > + * We can recover the pc in most cases, but in cases such as
> > + * calling function pointers we cannot. In this
> > + * case, default to using the lr. This will be
> > + * some address in the function, but will not
> > + * be the function start.
> > + * Unfortunately due to the stack frame layout we can't dump
> > + * r0 - r3, but these are less frequently saved.
> > + *
> > + * Stack frame layout:
> > + * <larger addresses>
> > + * saved lr
> > + * frame => saved fp
> > + * optionally saved caller registers (r4 - r10)
> > + * optionally saved arguments (r0 - r3)
> > + * <top of stack frame>
> > + * <smaller addressses>
> > + *
> > + * Functions start with the following code sequence:
> > + * corrected pc => stmfd sp!, {..., fp, lr}
> > + * add fp, sp, #x
> > + * stmfd sp!, {r0 - r3} (optional)
> > + */
> > +#define sv_fp r5
> > +#define sv_pc r6
> > +#define sv_lr r8
> > + add frame, sp, #20 @ switch to false frame
> > +for_each_frame: tst frame, mask @ Check for address exceptions
> > + bne no_frame
> > +
> > +1001: ldr sv_pc, [frame, #4] @ get saved 'pc'
> > +1002: ldr sv_fp, [frame, #0] @ get saved fp
> > +
> > + teq sv_fp, #0 @ make sure next frame exists
> > + beq no_frame
> > +
> > +1003: ldr sv_lr, [sv_fp, #4] @ get saved lr from next frame
> > +
> > + //try to find function start
> > + ldr r0, [sv_lr, #-4] @ get call instruction
> > + ldr r3, .Ldsi+8
> > + and r2, r3, r0 @ is this a bl call
> > + teq r2, r3
> > + bne finished_setup @ give up if it's not
> > + and r0, #0xffffff @ get call offset 24-bit int
> > + lsl r0, r0, #8 @ sign extend offset
> > + asr r0, r0, #8
> > + ldr sv_pc, [sv_fp, #4] @ get lr address
> > + add sv_pc, sv_pc, #-4 @ get call instruction address
> > + add sv_pc, sv_pc, #8 @ take care of prefetch
> > + add sv_pc, sv_pc, r0, lsl #2 @ find function start
> > + b finished_setup
> > +
> > +finished_setup:
> > +
> > + bic sv_pc, sv_pc, mask @ mask PC/LR for the mode
> > +
> > +1004: mov r0, sv_pc
> > +
> > + mov r1, sv_lr
> > + mov r2, frame
> > + bic r1, r1, mask @ mask PC/LR for the mode
> > + bl dump_backtrace_entry
> > +
> > +1005: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, lr}
> > + ldr r3, .Ldsi @ instruction exists,
> > + teq r3, r1, lsr #11
> > + ldr r0, [frame] @ locals are stored in
> > + @ the preceding frame
> > + subeq r0, r0, #4
> > + bleq dump_backtrace_stm @ dump saved registers
> > +
> > + teq sv_fp, #0 @ zero saved fp means
> > + beq no_frame @ no further frames
> > +
> > + cmp sv_fp, frame @ next frame must be
> > + mov frame, sv_fp @ above the current frame
> > + bhi for_each_frame
> > +
> > +1006: adr r0, .Lbad
> > + mov r1, frame
> > + bl printk
> > +no_frame: ldmfd sp!, {r4 - r8, fp, pc}
> > +ENDPROC(c_backtrace)
> > + .pushsection __ex_table,"a"
> > + .align 3
> > + .long 1001b, 1006b
> > + .long 1002b, 1006b
> > + .long 1003b, 1006b
> > + .long 1004b, 1006b
> > + .popsection
> > +
> > +.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n"
> > + .align
> > +.Ldsi: .word 0xe92d4800 >> 11 @ stmfd sp!, {... fp, lr}
> > + .word 0xe92d0000 >> 11 @ stmfd sp!, {}
> > + .word 0x0b000000 @ bl if these bits are set
> > +
> > +ENDPROC(c_backtrace)
> > +
> > +#else
> > /*
> > * Stack frame layout:
> > * optionally saved caller registers (r4 - r10)
> > @@ -55,6 +161,15 @@ ENDPROC(c_backtrace)
> > * stmfd sp!, {r0 - r3} (optional)
> > * corrected pc => stmfd sp!, {..., fp, ip, lr, pc}
> > */
> > +#define sv_fp r5
> > +#define sv_pc r6
> > +#define offset r8
> > +
> > +1: stmfd sp!, {pc} @ calculate offset of PC stored
> > + ldr r0, [sp], #4 @ by stmfd for this CPU
> > + adr r1, 1b
> > + sub offset, r0, r1
> > +
> > for_each_frame: tst frame, mask @ Check for address exceptions
> > bne no_frame
> >
> > @@ -98,7 +213,7 @@ for_each_frame: tst frame, mask @ Check for address exceptions
> > 1006: adr r0, .Lbad
> > mov r1, frame
> > bl printk
> > -no_frame: ldmfd sp!, {r4 - r8, pc}
> > +no_frame: ldmfd sp!, {r4 - r8, fp, pc}
> > ENDPROC(c_backtrace)
> >
> > .pushsection __ex_table,"a"
> > @@ -115,3 +230,4 @@ ENDPROC(c_backtrace)
> > .word 0xe92d0000 >> 11 @ stmfd sp!, {}
> >
> > #endif
> > +#endif
> >
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox