summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/arith.c7
-rw-r--r--runtime/copy.c5
-rw-r--r--runtime/current.c33
-rw-r--r--runtime/loc2c-runtime.h158
-rw-r--r--runtime/regs.h9
-rw-r--r--runtime/stack-s390.c82
-rw-r--r--runtime/stack.c2
7 files changed, 296 insertions, 0 deletions
diff --git a/runtime/arith.c b/runtime/arith.c
index fea7421a..97121ae8 100644
--- a/runtime/arith.c
+++ b/runtime/arith.c
@@ -25,6 +25,13 @@ long long _div64 (long long u, long long v);
long long _mod64 (long long u, long long v);
#endif
+/* 31 bit s390 suupport is not yet included, it may never be.
+#ifdef __s390__
+long long _div64 (long long u, long long v);
+long long _mod64 (long long u, long long v);
+#endif
+*/
+
/** Divide x by y. In case of division-by-zero,
* set context error string, and return 0
*/
diff --git a/runtime/copy.c b/runtime/copy.c
index f4d906b3..4d716861 100644
--- a/runtime/copy.c
+++ b/runtime/copy.c
@@ -88,6 +88,11 @@ do { \
#elif defined (__powerpc64__) || defined (__ia64__)
#define __stp_strncpy_from_user(dst,src,count,res) \
do { res = __strncpy_from_user(dst, src, count); } while(0)
+
+#elif defined (__s390__) || defined (__s390x__)
+#define __stp_strncpy_from_user(dst,src,count,res) \
+ do { res = strncpy_from_user(dst, src, count); } while(0)
+
#endif
/** Copy a NULL-terminated string from userspace.
diff --git a/runtime/current.c b/runtime/current.c
index 5dbc06ef..809f253b 100644
--- a/runtime/current.c
+++ b/runtime/current.c
@@ -44,6 +44,8 @@ unsigned long _stp_ret_addr (struct pt_regs *regs)
return REG_LINK(regs);
#elif defined (__ia64__)
return regs->b0;
+#elif defined (__s390__) || defined (__s390x__)
+ return regs->gprs[14];
#else
#error Unimplemented architecture
#endif
@@ -208,6 +210,37 @@ void _stp_sprint_regs(String str, struct pt_regs * regs)
_stp_string_cat(str, "\n");
}
+#elif defined (__s390x__) || defined (__s390__)
+
+#ifdef __s390x__
+#define GPRSIZE "%016lX "
+#else /* s390 */
+#define GPRSIZE "%08lX "
+#endif
+
+void _stp_sprint_regs(String str, struct pt_regs * regs)
+{
+ char *mode;
+ int i;
+
+ mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
+ _stp_sprintf(str,"%s PSW : ["GPRSIZE"] ["GPRSIZE"]",
+ mode, (void *) regs->psw.mask,
+ (void *) regs->psw.addr);
+
+#ifdef CONFIG_SMP
+ _stp_sprintf(str, " CPU: %d", smp_processor_id());
+#endif /* CONFIG_SMP */
+
+ for (i = 0; i < 16; i++) {
+ if ((i % 4) == 0) {
+ _stp_sprintf(str, "\n GPRS%02d: ", i);
+ }
+ _stp_sprintf(str, GPRSIZE, regs->gprs[i]);
+ }
+ _stp_string_cat(str, "\n");
+}
+
#endif
/** Print the registers.
diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h
index c88ad97e..493f0193 100644
--- a/runtime/loc2c-runtime.h
+++ b/runtime/loc2c-runtime.h
@@ -112,6 +112,12 @@
#define fetch_register(regno) ((intptr_t) c->regs->gpr[regno])
#define store_register(regno) (c->regs->gpr[regno] = (value))
+#elif defined (__s390__) || defined (__s390x__)
+#undef fetch_register
+#undef store_register
+#define fetch_register(regno) ((intptr_t) c->regs->gprs[regno])
+#define store_register(regno) (c->regs->gprs[regno] = (value))
+
#endif
#if defined __i386__ || defined __x86_64__
@@ -254,8 +260,160 @@
goto deref_fault; \
})
+#elif defined (__s390__) || defined (__s390x__)
+
+#if defined __s390__
+#define __stp_get_asm(x, addr, err, size) \
+({ \
+ asm volatile( \
+ "0: mvc 0(%2,%4),0(%3)\n" \
+ "1:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "2: lhi %0,%5\n" \
+ " bras 1,3f\n" \
+ " .long 1b\n" \
+ "3: l 1,0(1)\n" \
+ " br 1\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 0b,2b\n" \
+ ".previous" \
+ : "+&d" (err), "=m" (x) \
+ : "i" (size),"a"(addr), \
+ "a" (&(x)),"K" (-EFAULT) \
+ : "cc", "1" ); \
+})
+
+#define __stp_put_asm(x, addr, err, size) \
+({ \
+ asm volatile( \
+ "0: mvc 0(%1,%2),0(%3)\n" \
+ "1:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "2: lhi %0,%5\n" \
+ " bras 1,3f\n" \
+ " .long 1b\n" \
+ "3: l 1,0(1)\n" \
+ " br 1\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 4\n" \
+ " .long 0b,2b\n" \
+ ".previous" \
+ : "+&d" (err) \
+ : "i" (size), "a" (addr), \
+ "a" (&(x)),"K" (-EFAULT) \
+ : "cc", "1"); \
+})
+
+#else /* s390x */
+
+#define __stp_get_asm(x, addr, err, size) \
+({ \
+ asm volatile( \
+ "0: mvc 0(%2,%4),0(%3)\n" \
+ "1:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "2: lghi %0,%5\n" \
+ " jg 1b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 8\n" \
+ " .quad 0b,2b\n" \
+ ".previous" \
+ : "+&d" (err), "=m" (x) \
+ : "i" (size),"a"(addr), \
+ "a" (&(x)),"K" (-EFAULT) \
+ : "cc"); \
+})
+
+#define __stp_put_asm(x, addr, err, size) \
+({ \
+ asm volatile( \
+ "0: mvc 0(%1,%2),0(%3)\n" \
+ "1:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "2: lghi %0,%4\n" \
+ " jg 1b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 8\n" \
+ " .quad 0b,2b\n" \
+ ".previous" \
+ : "+&d" (err) \
+ : "i" (size),"a"(addr), \
+ "a"(&(x)),"K"(-EFAULT) \
+ : "cc"); \
+})
#endif
+#define deref(size, addr) \
+({ \
+ u8 _b; u16 _w; u32 _l; u64 _q; \
+ int _bad = 0; \
+ intptr_t _v = 0; \
+ switch (size) { \
+ case 1: { \
+ __stp_get_asm(_b, addr, _bad, 1); \
+ _v = _b; \
+ break; \
+ }; \
+ case 2: { \
+ __stp_get_asm(_w, addr, _bad, 2); \
+ _v = _w; \
+ break; \
+ }; \
+ case 4: { \
+ __stp_get_asm(_l, addr, _bad, 4); \
+ _v = _l; \
+ break; \
+ }; \
+ case 8: { \
+ __stp_get_asm(_q, addr, _bad, 8); \
+ _v = _q; \
+ break; \
+ }; \
+ default: \
+ _bad = -EFAULT; \
+ } \
+ if (_bad) \
+ goto deref_fault; \
+ _v; \
+})
+
+#define deref_store(size, addr, value) \
+({ \
+ int _bad = 0; \
+ switch (size) { \
+ case 1:{ \
+ u8 _x = value; \
+ __stp_put_asm(_x, addr, _bad,1); \
+ break; \
+ }; \
+ case 2:{ \
+ u16 _x = value; \
+ __stp_put_asm(_x, addr, _bad,2); \
+ break; \
+ }; \
+ case 4:{ \
+ u32 _x = value; \
+ __stp_put_asm(_x, addr, _bad,4); \
+ break; \
+ }; \
+ case 8: { \
+ u64 _x = value; \
+ __stp_put_asm(_x, addr, _bad,8); \
+ break; \
+ }; \
+ default: \
+ break; \
+ } \
+ if (_bad) \
+ goto deref_fault; \
+})
+#endif /* (s390) || (s390x) */
+
#define deref_string(dst, addr, maxbytes) \
({ \
uintptr_t _addr; \
diff --git a/runtime/regs.h b/runtime/regs.h
index 0e759d1d..48487c4d 100644
--- a/runtime/regs.h
+++ b/runtime/regs.h
@@ -32,6 +32,15 @@
#define REG_SP(regs) regs->gpr[1]
#define REG_LINK(regs) regs->link
+#elif defined (__s390__) || defined (__s390x__)
+#ifndef __s390x__
+#define PSW_ADDR_AMODE 0x80000000UL
+#else /* __s390x__ */
+#define PSW_ADDR_AMODE 0x0000000000000000UL
+#endif /* __s390x__ */
+#define REG_IP(regs) ((regs)->psw.addr) | PSW_ADDR_AMODE
+#define REG_SP(regs) (regs)->gprs[15]
+
#else
#error "Unimplemented architecture"
#endif
diff --git a/runtime/stack-s390.c b/runtime/stack-s390.c
new file mode 100644
index 00000000..c65de741
--- /dev/null
+++ b/runtime/stack-s390.c
@@ -0,0 +1,82 @@
+/* -*- linux-c -*-
+ * ppc64 stack tracing functions
+ *
+ * This file is part of systemtap, and is free software. You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+static unsigned long
+__stp_show_stack (String str, unsigned long sp, unsigned long low,
+ unsigned long high, int verbose)
+{
+
+ struct stack_frame *sf;
+ struct pt_regs *regs;
+ unsigned long ip;
+
+ while (1) {
+ sp = sp & PSW_ADDR_INSN;
+ /* fixme: verify this is a kernel stack */
+ if (sp < low || sp > high - sizeof(*sf))
+ return sp;
+ sf = (struct stack_frame *) sp;
+ ip = sf->gprs[8] & PSW_ADDR_INSN;
+ if (verbose) {
+ _stp_sprintf(str, "[%016lx] [%016lx] ", sp, ip);
+ _stp_symbol_sprint(str, ip);
+ _stp_string_cat(str, "\n");
+ }else{
+ _stp_sprintf(str,"%lx ", ip);
+ }
+ /* Follow the back_chain */
+ while (1) {
+ low = sp;
+ sp = sf->back_chain & PSW_ADDR_INSN;
+ if (!sp)
+ break;
+ if (sp <= low || sp > high - sizeof(*sf))
+ return sp;
+ sf = (struct stack_frame *) sp;
+ ip = sf->gprs[8] & PSW_ADDR_INSN;
+ if (verbose) {
+ _stp_sprintf(str, "[%016lx] [%016lx] ", sp, ip);
+ _stp_symbol_sprint(str, ip);
+ _stp_string_cat(str, "\n");
+ }else{
+ _stp_sprintf(str,"%lx ", ip);
+ }
+ }
+ /* Zero backchain detected, check for interrupt frame. */
+ sp = (unsigned long) (sf + 1);
+ if (sp <= low || sp > high - sizeof(*regs))
+ return sp;
+ regs = (struct pt_regs *) sp;
+ if (verbose) {
+ _stp_sprintf(str, "[%016lx] [%016lx] ", sp, ip);
+ _stp_symbol_sprint(str, ip);
+ _stp_string_cat(str, "\n");
+ }else{
+ _stp_sprintf(str,"%lx ", ip);
+ }
+ low = sp;
+ sp = regs->gprs[15];
+ }
+}
+
+static void __stp_stack_sprint (String str, struct pt_regs *regs,
+ int verbose, int levels)
+{
+ unsigned long *_sp = (unsigned long *)&REG_SP(regs);
+ unsigned long sp = (unsigned long)_sp;
+ // unsigned long sp = (unsigned long)*_sp;
+
+ sp = __stp_show_stack(str, sp,
+ S390_lowcore.async_stack - ASYNC_SIZE,
+ S390_lowcore.async_stack,verbose);
+
+ __stp_show_stack(str, sp,
+ S390_lowcore.thread_info,
+ S390_lowcore.thread_info + THREAD_SIZE,verbose);
+}
diff --git a/runtime/stack.c b/runtime/stack.c
index a52dbfee..72a57e19 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -34,6 +34,8 @@ static int _stp_kta(unsigned long addr);
#include "stack-i386.c"
#elif defined (__powerpc64__)
#include "stack-ppc64.c"
+#elif defined (__s390__) || defined (__s390x__)
+#include "stack-s390.c"
#else
#error "Unsupported architecture"
#endif