From: Sven Schnelle <svens@stackframe.org>
To: Helge Deller <deller@gmx.de>
Cc: linux-parisc@vger.kernel.org
Subject: [PATCH 2/2] parisc: add support for TOC (transfer of control)
Date: Sat, 9 Oct 2021 23:38:56 +0200 [thread overview]
Message-ID: <20211009213856.3326-3-svens@stackframe.org> (raw)
In-Reply-To: <20211009213856.3326-1-svens@stackframe.org>
Almost all PA-RISC machines have either a button that
is labeled with 'TOC' or a BMC function to trigger a TOC.
TOC is a non-maskable interrupt that is sent to the processor.
This can be used for diagnostic purposes like obtaining a
stack trace/register dump or to enter KDB/KGDB.
As an example, on my c8000, TOC can be used with:
CONFIG_KGDB=y
CONFIG_KGDB_KDB=y
and the 'kgdboc=ttyS0,115200' appended to the command line.
Press ^( on serial console, which will enter the BMC command line,
and enter 'TOC s':
root@(none):/# (
cli>TOC s
Sending TOC/INIT.
<Cpu3> 2800035d03e00000 0000000040c21ac8 CC_ERR_CHECK_TOC
<Cpu0> 2800035d00e00000 0000000040c21ad0 CC_ERR_CHECK_TOC
<Cpu2> 2800035d02e00000 0000000040c21ac8 CC_ERR_CHECK_TOC
<Cpu1> 2800035d01e00000 0000000040c21ad0 CC_ERR_CHECK_TOC
<Cpu3> 37000f7303e00000 2000000000000000 CC_ERR_CPU_CHECK_SUMMARY
<Cpu0> 37000f7300e00000 2000000000000000 CC_ERR_CPU_CHECK_SUMMARY
<Cpu2> 37000f7302e00000 2000000000000000 CC_ERR_CPU_CHECK_SUMMARY
<Cpu1> 37000f7301e00000 2000000000000000 CC_ERR_CPU_CHECK_SUMMARY
<Cpu3> 4300100803e00000 c0000000001d26cc CC_MC_BR_TO_OS_TOC
<Cpu0> 4300100800e00000 c0000000001d26cc CC_MC_BR_TO_OS_TOC
<Cpu2> 4300100802e00000 c0000000001d26cc CC_MC_BR_TO_OS_TOC
<Cpu1> 4300100801e00000 c0000000001d26cc CC_MC_BR_TO_OS_TOC
Entering kdb (current=0x00000000411cef80, pid 0) on processor 0 due to NonMaskable Interrupt @ 0x40c21ad0
[0]kdb>
Signed-off-by: Sven Schnelle <svens@stackframe.org>
---
arch/parisc/include/asm/processor.h | 4 ++
arch/parisc/include/uapi/asm/pdc.h | 6 ++-
arch/parisc/kernel/entry.S | 69 +++++++++++++++++++++++++
arch/parisc/kernel/processor.c | 21 ++++++++
arch/parisc/kernel/traps.c | 79 +++++++++++++++++++++++++++++
5 files changed, 177 insertions(+), 2 deletions(-)
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h
index eeb7da064289..1e9a4c986921 100644
--- a/arch/parisc/include/asm/processor.h
+++ b/arch/parisc/include/asm/processor.h
@@ -294,6 +294,10 @@ extern int _parisc_requires_coherency;
extern int running_on_qemu;
+extern void toc_handler(void);
+extern unsigned int toc_handler_size;
+extern unsigned int toc_handler_csum;
+
#endif /* __ASSEMBLY__ */
#endif /* __ASM_PARISC_PROCESSOR_H */
diff --git a/arch/parisc/include/uapi/asm/pdc.h b/arch/parisc/include/uapi/asm/pdc.h
index ad51df8ba952..acc633c15722 100644
--- a/arch/parisc/include/uapi/asm/pdc.h
+++ b/arch/parisc/include/uapi/asm/pdc.h
@@ -398,8 +398,10 @@ struct zeropage {
/* int (*vec_rendz)(void); */
unsigned int vec_rendz;
int vec_pow_fail_flen;
- int vec_pad[10];
-
+ int vec_pad0[3];
+ unsigned int vec_toc_hi;
+ int vec_pad1[6];
+
/* [0x040] reserved processor dependent */
int pad0[112];
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 9f939afe6b88..f486f3b51075 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -28,6 +28,7 @@
#include <linux/linkage.h>
#include <linux/pgtable.h>
+#include <linux/threads.h>
#ifdef CONFIG_64BIT
.level 2.0w
@@ -2414,3 +2415,71 @@ ENTRY_CFI(set_register)
copy %r1,%r31
ENDPROC_CFI(set_register)
+ .import toc_intr,code
+ ENTRY_CFI(toc_handler)
+ /*
+ * synchronize CPUs and obtain offset
+ * for stack setup.
+ */
+ load32 PA(toc_lock),%r1
+0: ldcw,co 0(%r1),%r2
+ cmpib,= 0,%r2,0b
+ nop
+ addi 1,%r2,%r4
+ stw %r4,0(%r1)
+ addi -1,%r2,%r4
+
+ load32 PA(toc_stack),sp
+ /*
+ * deposit CPU number into stack address,
+ * so every CPU will have its own stack.
+ */
+ depw %r4,18,2,%sp
+
+ /* setup pt_regs on stack and save the
+ * floating point registers. PIM_TOC doesn't
+ * save fp registers, so we're doing it here.
+ */
+ copy %sp,%arg0
+ ldo PT_SZ_ALGN(%sp), %sp
+
+ /* clear pt_regs */
+ copy %arg0,%r1
+0: cmpb,<<,n %r1,%sp,0b
+ stw,ma %r0,4(%r1)
+
+ ldo PT_FR0(%arg0),%r25
+ save_fp %r25
+
+ /* go virtual */
+ load32 PA(swapper_pg_dir),%r4
+ mtctl %r4,%cr24
+ mtctl %r4,%cr25
+
+ /* Clear sr4-sr7 */
+ mtsp %r0, %sr4
+ mtsp %r0, %sr5
+ mtsp %r0, %sr6
+ mtsp %r0, %sr7
+
+ tovirt_r1 %sp
+ tovirt_r1 %arg0
+ virt_map
+
+ loadgp
+#ifdef CONFIG_64BIT
+ ldo -16(%sp),%r29
+#endif
+ b,l toc_intr,%r2
+ nop
+0: b 0b
+ENDPROC_CFI(toc_handler)
+
+SYM_DATA(toc_handler_csum, .long 0)
+SYM_DATA(toc_handler_size, .long . - toc_handler)
+SYM_DATA(toc_lock, .long 1)
+
+ __PAGE_ALIGNED_BSS
+ .align 16384*NR_CPUS
+toc_stack:
+ .block 16384*NR_CPUS
diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c
index 1b6129e7d776..582caf99d952 100644
--- a/arch/parisc/kernel/processor.c
+++ b/arch/parisc/kernel/processor.c
@@ -28,6 +28,7 @@
#include <asm/pdcpat.h>
#include <asm/irq.h> /* for struct irq_region */
#include <asm/parisc-device.h>
+#include <asm/sections.h>
struct system_cpuinfo_parisc boot_cpu_data __ro_after_init;
EXPORT_SYMBOL(boot_cpu_data);
@@ -453,6 +454,25 @@ static struct parisc_driver cpu_driver __refdata = {
.probe = processor_probe
};
+static __init void setup_toc(void)
+{
+ unsigned int csum = 0;
+ unsigned long toc_code = (unsigned long)dereference_function_descriptor(toc_handler);
+ int i;
+
+ PAGE0->vec_toc = __pa(toc_code) & 0xffffffff;
+#ifdef CONFIG_64BIT
+ PAGE0->vec_toc_hi = __pa(toc_code) >> 32;
+#else
+ PAGE0->vec_toc_hi = 0;
+#endif
+ PAGE0->vec_toclen = toc_handler_size;
+
+ for (i = 0; i < toc_handler_size/4; i++)
+ csum += ((u32 *)toc_code)[i];
+ toc_handler_csum = -csum;
+}
+
/**
* processor_init - Processor initialization procedure.
*
@@ -460,5 +480,6 @@ static struct parisc_driver cpu_driver __refdata = {
*/
void __init processor_init(void)
{
+ setup_toc();
register_parisc_driver(&cpu_driver);
}
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 747c328fb886..e847d37eda3a 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -30,6 +30,8 @@
#include <linux/ratelimit.h>
#include <linux/uaccess.h>
#include <linux/kdebug.h>
+#include <linux/kdb.h>
+#include <linux/reboot.h>
#include <asm/assembly.h>
#include <asm/io.h>
@@ -472,6 +474,83 @@ void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long o
panic(msg);
}
+static void toc20_to_pt_regs(struct pt_regs *regs, struct pdc_toc_pim_20 *toc)
+{
+ int i;
+
+ regs->gr[0] = (unsigned long)toc->cr[22];
+
+ for (i = 1; i < 32; i++)
+ regs->gr[i] = (unsigned long)toc->gr[i];
+
+ for (i = 0; i < 8; i++)
+ regs->sr[i] = (unsigned long)toc->sr[i];
+
+ regs->iasq[0] = (unsigned long)toc->cr[17];
+ regs->iasq[1] = (unsigned long)toc->iasq_back;
+ regs->iaoq[0] = (unsigned long)toc->cr[18];
+ regs->iaoq[1] = (unsigned long)toc->iaoq_back;
+
+ regs->sar = (unsigned long)toc->cr[11];
+ regs->iir = (unsigned long)toc->cr[19];
+ regs->isr = (unsigned long)toc->cr[20];
+ regs->ior = (unsigned long)toc->cr[21];
+}
+
+static void toc11_to_pt_regs(struct pt_regs *regs, struct pdc_toc_pim_11 *toc)
+{
+ int i;
+
+ regs->gr[0] = toc->cr[22];
+
+ for (i = 1; i < 32; i++)
+ regs->gr[i] = toc->gr[i];
+
+ for (i = 0; i < 8; i++)
+ regs->sr[i] = toc->sr[i];
+
+ regs->iasq[0] = toc->cr[17];
+ regs->iasq[1] = toc->iasq_back;
+ regs->iaoq[0] = toc->cr[18];
+ regs->iaoq[1] = toc->iaoq_back;
+
+ regs->sar = toc->cr[11];
+ regs->iir = toc->cr[19];
+ regs->isr = toc->cr[20];
+ regs->ior = toc->cr[21];
+}
+
+void notrace toc_intr(struct pt_regs *regs)
+{
+ struct pdc_toc_pim_20 pim_data20;
+ struct pdc_toc_pim_11 pim_data11;
+
+ nmi_enter();
+
+ if (boot_cpu_data.cpu_type >= pcxu) {
+ if (pdc_pim_toc20(&pim_data20))
+ panic("Failed to get PIM data");
+ toc20_to_pt_regs(regs, &pim_data20);
+ } else {
+ if (pdc_pim_toc11(&pim_data11))
+ panic("Failed to get PIM data");
+ toc11_to_pt_regs(regs, &pim_data11);
+ }
+
+#ifdef CONFIG_KGDB
+ if (atomic_read(&kgdb_active) != -1)
+ kgdb_nmicallback(raw_smp_processor_id(), regs);
+ kgdb_handle_exception(KDB_REASON_SYSTEM_NMI, SIGTRAP, 0, regs);
+#endif
+ show_regs(regs);
+
+ /* give other CPUs time to show their backtrace */
+ mdelay(2000);
+ machine_restart("TOC");
+
+ nmi_exit();
+}
+
void notrace handle_interruption(int code, struct pt_regs *regs)
{
unsigned long fault_address = 0;
--
2.33.0
next prev parent reply other threads:[~2021-10-09 21:39 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-10-09 21:38 [PATCH 0/2] add TOC support Sven Schnelle
2021-10-09 21:38 ` [PATCH 1/2] parisc/firmware: add functions to retrieve TOC data Sven Schnelle
2021-10-09 21:38 ` Sven Schnelle [this message]
2021-10-10 9:13 ` [PATCH 2/2] parisc: add support for TOC (transfer of control) Helge Deller
2021-10-10 11:42 ` Sven Schnelle
-- strict thread matches above, loose matches on Subject: below --
2021-10-10 18:38 [PATCH v2 0/2] add TOC support Sven Schnelle
2021-10-10 18:38 ` [PATCH 2/2] parisc: add support for TOC (transfer of control) Sven Schnelle
2021-10-10 19:31 ` Helge Deller
2021-10-10 19:36 ` Sven Schnelle
2021-10-12 10:03 ` Helge Deller
2021-10-15 16:22 ` Rolf Eike Beer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211009213856.3326-3-svens@stackframe.org \
--to=svens@stackframe.org \
--cc=deller@gmx.de \
--cc=linux-parisc@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.