Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky: - Add the CPU id for the new z13s machine - Add a s390 specific XOR template for RAID-5 checksumming based on the XC instruction. Remove all other alternatives, XC is always faster - The merge of our four different stack tracers into a single one - Tidy up the code related to page tables, several large inline functions are now out-of-line. Bloat-o-meter reports ~11K text size reduction - A binary interface for the priviledged CLP instruction to retrieve the hardware view of the installed PCI functions - Improvements for the dasd format code - Bug fixes and cleanups * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (31 commits) s390/pci: enforce fmb page boundary rule s390: fix floating pointer register corruption (again) s390/cpumf: add missing lpp magic initialization s390: Fix misspellings in comments s390/mm: split arch/s390/mm/pgtable.c s390/mm: uninline pmdp_xxx functions from pgtable.h s390/mm: uninline ptep_xxx functions from pgtable.h s390/pci: add ioctl interface for CLP s390: Use pr_warn instead of pr_warning s390/dasd: remove casts to dasd_*_private s390/dasd: Refactor dasd format functions s390/dasd: Simplify code in format logic s390/dasd: Improve dasd format code s390/percpu: remove this_cpu_cmpxchg_double_4 s390/cpumf: Improve guest detection heuristics s390/fault: merge report_user_fault implementations s390/dis: use correct escape sequence for '%' character s390/kvm: simplify set_guest_storage_key s390/oprofile: add z13/z13s model numbers s390: add z13s model number to z13 elf platform ...
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
#include <asm/idle.h>
|
||||
#include <asm/vdso.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/gmap.h>
|
||||
|
||||
/*
|
||||
* Make sure that the compiler is new enough. We want a compiler that
|
||||
|
@@ -96,8 +96,7 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
|
||||
(((unsigned long)response + rlen) >> 31)) {
|
||||
lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
|
||||
if (!lowbuf) {
|
||||
pr_warning("The cpcmd kernel function failed to "
|
||||
"allocate a response buffer\n");
|
||||
pr_warn("The cpcmd kernel function failed to allocate a response buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
spin_lock_irqsave(&cpcmd_lock, flags);
|
||||
|
@@ -699,8 +699,7 @@ debug_info_t *debug_register_mode(const char *name, int pages_per_area,
|
||||
/* Since debugfs currently does not support uid/gid other than root, */
|
||||
/* we do not allow gid/uid != 0 until we get support for that. */
|
||||
if ((uid != 0) || (gid != 0))
|
||||
pr_warning("Root becomes the owner of all s390dbf files "
|
||||
"in sysfs\n");
|
||||
pr_warn("Root becomes the owner of all s390dbf files in sysfs\n");
|
||||
BUG_ON(!initialized);
|
||||
mutex_lock(&debug_mutex);
|
||||
|
||||
@@ -1307,8 +1306,7 @@ debug_input_level_fn(debug_info_t * id, struct debug_view *view,
|
||||
new_level = debug_get_uint(str);
|
||||
}
|
||||
if(new_level < 0) {
|
||||
pr_warning("%s is not a valid level for a debug "
|
||||
"feature\n", str);
|
||||
pr_warn("%s is not a valid level for a debug feature\n", str);
|
||||
rc = -EINVAL;
|
||||
} else {
|
||||
debug_set_level(id, new_level);
|
||||
|
@@ -1920,23 +1920,16 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
|
||||
}
|
||||
if (separator)
|
||||
ptr += sprintf(ptr, "%c", separator);
|
||||
/*
|
||||
* Use four '%' characters below because of the
|
||||
* following two conversions:
|
||||
*
|
||||
* 1) sprintf: %%%%r -> %%r
|
||||
* 2) printk : %%r -> %r
|
||||
*/
|
||||
if (operand->flags & OPERAND_GPR)
|
||||
ptr += sprintf(ptr, "%%%%r%i", value);
|
||||
ptr += sprintf(ptr, "%%r%i", value);
|
||||
else if (operand->flags & OPERAND_FPR)
|
||||
ptr += sprintf(ptr, "%%%%f%i", value);
|
||||
ptr += sprintf(ptr, "%%f%i", value);
|
||||
else if (operand->flags & OPERAND_AR)
|
||||
ptr += sprintf(ptr, "%%%%a%i", value);
|
||||
ptr += sprintf(ptr, "%%a%i", value);
|
||||
else if (operand->flags & OPERAND_CR)
|
||||
ptr += sprintf(ptr, "%%%%c%i", value);
|
||||
ptr += sprintf(ptr, "%%c%i", value);
|
||||
else if (operand->flags & OPERAND_VR)
|
||||
ptr += sprintf(ptr, "%%%%v%i", value);
|
||||
ptr += sprintf(ptr, "%%v%i", value);
|
||||
else if (operand->flags & OPERAND_PCREL)
|
||||
ptr += sprintf(ptr, "%lx", (signed int) value
|
||||
+ addr);
|
||||
|
@@ -19,28 +19,28 @@
|
||||
#include <asm/ipl.h>
|
||||
|
||||
/*
|
||||
* For show_trace we have tree different stack to consider:
|
||||
* For dump_trace we have tree different stack to consider:
|
||||
* - the panic stack which is used if the kernel stack has overflown
|
||||
* - the asynchronous interrupt stack (cpu related)
|
||||
* - the synchronous kernel stack (process related)
|
||||
* The stack trace can start at any of the three stack and can potentially
|
||||
* The stack trace can start at any of the three stacks and can potentially
|
||||
* touch all of them. The order is: panic stack, async stack, sync stack.
|
||||
*/
|
||||
static unsigned long
|
||||
__show_trace(unsigned long sp, unsigned long low, unsigned long high)
|
||||
__dump_trace(dump_trace_func_t func, void *data, unsigned long sp,
|
||||
unsigned long low, unsigned long high)
|
||||
{
|
||||
struct stack_frame *sf;
|
||||
struct pt_regs *regs;
|
||||
unsigned long addr;
|
||||
|
||||
while (1) {
|
||||
if (sp < low || sp > high - sizeof(*sf))
|
||||
return sp;
|
||||
sf = (struct stack_frame *) sp;
|
||||
addr = sf->gprs[8];
|
||||
printk("([<%016lx>] %pSR)\n", addr, (void *)addr);
|
||||
/* Follow the backchain. */
|
||||
while (1) {
|
||||
if (func(data, sf->gprs[8]))
|
||||
return sp;
|
||||
low = sp;
|
||||
sp = sf->back_chain;
|
||||
if (!sp)
|
||||
@@ -48,46 +48,58 @@ __show_trace(unsigned long sp, unsigned long low, unsigned long high)
|
||||
if (sp <= low || sp > high - sizeof(*sf))
|
||||
return sp;
|
||||
sf = (struct stack_frame *) sp;
|
||||
addr = sf->gprs[8];
|
||||
printk(" [<%016lx>] %pSR\n", addr, (void *)addr);
|
||||
}
|
||||
/* 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;
|
||||
addr = regs->psw.addr;
|
||||
printk(" [<%016lx>] %pSR\n", addr, (void *)addr);
|
||||
if (!user_mode(regs)) {
|
||||
if (func(data, regs->psw.addr))
|
||||
return sp;
|
||||
}
|
||||
low = sp;
|
||||
sp = regs->gprs[15];
|
||||
}
|
||||
}
|
||||
|
||||
static void show_trace(struct task_struct *task, unsigned long *stack)
|
||||
void dump_trace(dump_trace_func_t func, void *data, struct task_struct *task,
|
||||
unsigned long sp)
|
||||
{
|
||||
const unsigned long frame_size =
|
||||
STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
|
||||
register unsigned long __r15 asm ("15");
|
||||
unsigned long sp;
|
||||
unsigned long frame_size;
|
||||
|
||||
sp = (unsigned long) stack;
|
||||
if (!sp)
|
||||
sp = task ? task->thread.ksp : __r15;
|
||||
printk("Call Trace:\n");
|
||||
frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
|
||||
#ifdef CONFIG_CHECK_STACK
|
||||
sp = __show_trace(sp,
|
||||
sp = __dump_trace(func, data, sp,
|
||||
S390_lowcore.panic_stack + frame_size - 4096,
|
||||
S390_lowcore.panic_stack + frame_size);
|
||||
#endif
|
||||
sp = __show_trace(sp,
|
||||
sp = __dump_trace(func, data, sp,
|
||||
S390_lowcore.async_stack + frame_size - ASYNC_SIZE,
|
||||
S390_lowcore.async_stack + frame_size);
|
||||
if (task)
|
||||
__show_trace(sp, (unsigned long) task_stack_page(task),
|
||||
(unsigned long) task_stack_page(task) + THREAD_SIZE);
|
||||
__dump_trace(func, data, sp,
|
||||
(unsigned long)task_stack_page(task),
|
||||
(unsigned long)task_stack_page(task) + THREAD_SIZE);
|
||||
else
|
||||
__show_trace(sp, S390_lowcore.thread_info,
|
||||
__dump_trace(func, data, sp,
|
||||
S390_lowcore.thread_info,
|
||||
S390_lowcore.thread_info + THREAD_SIZE);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dump_trace);
|
||||
|
||||
static int show_address(void *data, unsigned long address)
|
||||
{
|
||||
printk("([<%016lx>] %pSR)\n", address, (void *)address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void show_trace(struct task_struct *task, unsigned long sp)
|
||||
{
|
||||
if (!sp)
|
||||
sp = task ? task->thread.ksp : current_stack_pointer();
|
||||
printk("Call Trace:\n");
|
||||
dump_trace(show_address, NULL, task, sp);
|
||||
if (!task)
|
||||
task = current;
|
||||
debug_show_held_locks(task);
|
||||
@@ -95,15 +107,16 @@ static void show_trace(struct task_struct *task, unsigned long *stack)
|
||||
|
||||
void show_stack(struct task_struct *task, unsigned long *sp)
|
||||
{
|
||||
register unsigned long *__r15 asm ("15");
|
||||
unsigned long *stack;
|
||||
int i;
|
||||
|
||||
if (!sp)
|
||||
stack = task ? (unsigned long *) task->thread.ksp : __r15;
|
||||
else
|
||||
stack = sp;
|
||||
|
||||
stack = sp;
|
||||
if (!stack) {
|
||||
if (!task)
|
||||
stack = (unsigned long *)current_stack_pointer();
|
||||
else
|
||||
stack = (unsigned long *)task->thread.ksp;
|
||||
}
|
||||
for (i = 0; i < 20; i++) {
|
||||
if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
|
||||
break;
|
||||
@@ -112,7 +125,7 @@ void show_stack(struct task_struct *task, unsigned long *sp)
|
||||
printk("%016lx ", *stack++);
|
||||
}
|
||||
printk("\n");
|
||||
show_trace(task, sp);
|
||||
show_trace(task, (unsigned long)sp);
|
||||
}
|
||||
|
||||
static void show_last_breaking_event(struct pt_regs *regs)
|
||||
@@ -121,13 +134,9 @@ static void show_last_breaking_event(struct pt_regs *regs)
|
||||
printk(" [<%016lx>] %pSR\n", regs->args[0], (void *)regs->args[0]);
|
||||
}
|
||||
|
||||
static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
|
||||
{
|
||||
return (regs->psw.mask & bits) / ((~bits + 1) & bits);
|
||||
}
|
||||
|
||||
void show_registers(struct pt_regs *regs)
|
||||
{
|
||||
struct psw_bits *psw = &psw_bits(regs->psw);
|
||||
char *mode;
|
||||
|
||||
mode = user_mode(regs) ? "User" : "Krnl";
|
||||
@@ -136,13 +145,9 @@ void show_registers(struct pt_regs *regs)
|
||||
printk(" (%pSR)", (void *)regs->psw.addr);
|
||||
printk("\n");
|
||||
printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
|
||||
"P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER),
|
||||
mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO),
|
||||
mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY),
|
||||
mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT),
|
||||
mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC),
|
||||
mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM));
|
||||
printk(" EA:%x", mask_bits(regs, PSW_MASK_EA | PSW_MASK_BA));
|
||||
"P:%x AS:%x CC:%x PM:%x", psw->r, psw->t, psw->i, psw->e,
|
||||
psw->key, psw->m, psw->w, psw->p, psw->as, psw->cc, psw->pm);
|
||||
printk(" RI:%x EA:%x", psw->ri, psw->eaba);
|
||||
printk("\n%s GPRS: %016lx %016lx %016lx %016lx\n", mode,
|
||||
regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
|
||||
printk(" %016lx %016lx %016lx %016lx\n",
|
||||
@@ -160,7 +165,7 @@ void show_regs(struct pt_regs *regs)
|
||||
show_registers(regs);
|
||||
/* Show stack backtrace if pt_regs is from kernel mode */
|
||||
if (!user_mode(regs))
|
||||
show_trace(NULL, (unsigned long *) regs->gprs[15]);
|
||||
show_trace(NULL, regs->gprs[15]);
|
||||
show_last_breaking_event(regs);
|
||||
}
|
||||
|
||||
|
@@ -186,6 +186,7 @@ ENTRY(__switch_to)
|
||||
stg %r5,__LC_THREAD_INFO # store thread info of next
|
||||
stg %r15,__LC_KERNEL_STACK # store end of kernel stack
|
||||
lg %r15,__THREAD_ksp(%r1) # load kernel stack of next
|
||||
/* c4 is used in guest detection: arch/s390/kernel/perf_cpum_sf.c */
|
||||
lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
|
||||
mvc __LC_CURRENT_PID(4,%r0),__TASK_pid(%r3) # store pid of next
|
||||
lmg %r6,%r15,__SF_GPRS(%r15) # load gprs of next task
|
||||
@@ -1199,114 +1200,12 @@ cleanup_critical:
|
||||
.quad .Lpsw_idle_lpsw
|
||||
|
||||
.Lcleanup_save_fpu_regs:
|
||||
TSTMSK __LC_CPU_FLAGS,_CIF_FPU
|
||||
bor %r14
|
||||
clg %r9,BASED(.Lcleanup_save_fpu_regs_done)
|
||||
jhe 5f
|
||||
clg %r9,BASED(.Lcleanup_save_fpu_regs_fp)
|
||||
jhe 4f
|
||||
clg %r9,BASED(.Lcleanup_save_fpu_regs_vx_high)
|
||||
jhe 3f
|
||||
clg %r9,BASED(.Lcleanup_save_fpu_regs_vx_low)
|
||||
jhe 2f
|
||||
clg %r9,BASED(.Lcleanup_save_fpu_fpc_end)
|
||||
jhe 1f
|
||||
lg %r2,__LC_CURRENT
|
||||
aghi %r2,__TASK_thread
|
||||
0: # Store floating-point controls
|
||||
stfpc __THREAD_FPU_fpc(%r2)
|
||||
1: # Load register save area and check if VX is active
|
||||
lg %r3,__THREAD_FPU_regs(%r2)
|
||||
TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
|
||||
jz 4f # no VX -> store FP regs
|
||||
2: # Store vector registers (V0-V15)
|
||||
VSTM %v0,%v15,0,%r3 # vstm 0,15,0(3)
|
||||
3: # Store vector registers (V16-V31)
|
||||
VSTM %v16,%v31,256,%r3 # vstm 16,31,256(3)
|
||||
j 5f # -> done, set CIF_FPU flag
|
||||
4: # Store floating-point registers
|
||||
std 0,0(%r3)
|
||||
std 1,8(%r3)
|
||||
std 2,16(%r3)
|
||||
std 3,24(%r3)
|
||||
std 4,32(%r3)
|
||||
std 5,40(%r3)
|
||||
std 6,48(%r3)
|
||||
std 7,56(%r3)
|
||||
std 8,64(%r3)
|
||||
std 9,72(%r3)
|
||||
std 10,80(%r3)
|
||||
std 11,88(%r3)
|
||||
std 12,96(%r3)
|
||||
std 13,104(%r3)
|
||||
std 14,112(%r3)
|
||||
std 15,120(%r3)
|
||||
5: # Set CIF_FPU flag
|
||||
oi __LC_CPU_FLAGS+7,_CIF_FPU
|
||||
lg %r9,48(%r11) # return from save_fpu_regs
|
||||
larl %r9,save_fpu_regs
|
||||
br %r14
|
||||
.Lcleanup_save_fpu_fpc_end:
|
||||
.quad .Lsave_fpu_regs_fpc_end
|
||||
.Lcleanup_save_fpu_regs_vx_low:
|
||||
.quad .Lsave_fpu_regs_vx_low
|
||||
.Lcleanup_save_fpu_regs_vx_high:
|
||||
.quad .Lsave_fpu_regs_vx_high
|
||||
.Lcleanup_save_fpu_regs_fp:
|
||||
.quad .Lsave_fpu_regs_fp
|
||||
.Lcleanup_save_fpu_regs_done:
|
||||
.quad .Lsave_fpu_regs_done
|
||||
|
||||
.Lcleanup_load_fpu_regs:
|
||||
TSTMSK __LC_CPU_FLAGS,_CIF_FPU
|
||||
bnor %r14
|
||||
clg %r9,BASED(.Lcleanup_load_fpu_regs_done)
|
||||
jhe 1f
|
||||
clg %r9,BASED(.Lcleanup_load_fpu_regs_fp)
|
||||
jhe 2f
|
||||
clg %r9,BASED(.Lcleanup_load_fpu_regs_vx_high)
|
||||
jhe 3f
|
||||
clg %r9,BASED(.Lcleanup_load_fpu_regs_vx)
|
||||
jhe 4f
|
||||
lg %r4,__LC_CURRENT
|
||||
aghi %r4,__TASK_thread
|
||||
lfpc __THREAD_FPU_fpc(%r4)
|
||||
TSTMSK __LC_MACHINE_FLAGS,MACHINE_FLAG_VX
|
||||
lg %r4,__THREAD_FPU_regs(%r4) # %r4 <- reg save area
|
||||
jz 2f # -> no VX, load FP regs
|
||||
4: # Load V0 ..V15 registers
|
||||
VLM %v0,%v15,0,%r4
|
||||
3: # Load V16..V31 registers
|
||||
VLM %v16,%v31,256,%r4
|
||||
j 1f
|
||||
2: # Load floating-point registers
|
||||
ld 0,0(%r4)
|
||||
ld 1,8(%r4)
|
||||
ld 2,16(%r4)
|
||||
ld 3,24(%r4)
|
||||
ld 4,32(%r4)
|
||||
ld 5,40(%r4)
|
||||
ld 6,48(%r4)
|
||||
ld 7,56(%r4)
|
||||
ld 8,64(%r4)
|
||||
ld 9,72(%r4)
|
||||
ld 10,80(%r4)
|
||||
ld 11,88(%r4)
|
||||
ld 12,96(%r4)
|
||||
ld 13,104(%r4)
|
||||
ld 14,112(%r4)
|
||||
ld 15,120(%r4)
|
||||
1: # Clear CIF_FPU bit
|
||||
ni __LC_CPU_FLAGS+7,255-_CIF_FPU
|
||||
lg %r9,48(%r11) # return from load_fpu_regs
|
||||
larl %r9,load_fpu_regs
|
||||
br %r14
|
||||
.Lcleanup_load_fpu_regs_vx:
|
||||
.quad .Lload_fpu_regs_vx
|
||||
.Lcleanup_load_fpu_regs_vx_high:
|
||||
.quad .Lload_fpu_regs_vx_high
|
||||
.Lcleanup_load_fpu_regs_fp:
|
||||
.quad .Lload_fpu_regs_fp
|
||||
.Lcleanup_load_fpu_regs_done:
|
||||
.quad .Lload_fpu_regs_done
|
||||
|
||||
/*
|
||||
* Integer constants
|
||||
|
@@ -164,8 +164,7 @@ void do_softirq_own_stack(void)
|
||||
{
|
||||
unsigned long old, new;
|
||||
|
||||
/* Get current stack pointer. */
|
||||
asm volatile("la %0,0(15)" : "=a" (old));
|
||||
old = current_stack_pointer();
|
||||
/* Check against async. stack address range. */
|
||||
new = S390_lowcore.async_stack;
|
||||
if (((new - old) >> (PAGE_SHIFT + THREAD_ORDER)) != 0) {
|
||||
|
@@ -383,7 +383,7 @@ static int __hw_perf_event_init(struct perf_event *event)
|
||||
|
||||
/* Validate the counter that is assigned to this event.
|
||||
* Because the counter facility can use numerous counters at the
|
||||
* same time without constraints, it is not necessary to explicity
|
||||
* same time without constraints, it is not necessary to explicitly
|
||||
* validate event groups (event->group_leader != event).
|
||||
*/
|
||||
err = validate_event(hwc);
|
||||
|
@@ -1022,10 +1022,13 @@ static int perf_push_sample(struct perf_event *event, struct sf_raw_sample *sfr)
|
||||
/*
|
||||
* A non-zero guest program parameter indicates a guest
|
||||
* sample.
|
||||
* Note that some early samples might be misaccounted to
|
||||
* the host.
|
||||
* Note that some early samples or samples from guests without
|
||||
* lpp usage would be misaccounted to the host. We use the asn
|
||||
* value as a heuristic to detect most of these guest samples.
|
||||
* If the value differs from the host hpp value, we assume
|
||||
* it to be a KVM guest.
|
||||
*/
|
||||
if (sfr->basic.gpp)
|
||||
if (sfr->basic.gpp || sfr->basic.prim_asn != (u16) sfr->basic.hpp)
|
||||
sde_regs->in_guest = 1;
|
||||
|
||||
overflow = 0;
|
||||
|
@@ -222,67 +222,23 @@ static int __init service_level_perf_register(void)
|
||||
}
|
||||
arch_initcall(service_level_perf_register);
|
||||
|
||||
/* See also arch/s390/kernel/traps.c */
|
||||
static unsigned long __store_trace(struct perf_callchain_entry *entry,
|
||||
unsigned long sp,
|
||||
unsigned long low, unsigned long high)
|
||||
static int __perf_callchain_kernel(void *data, unsigned long address)
|
||||
{
|
||||
struct stack_frame *sf;
|
||||
struct pt_regs *regs;
|
||||
struct perf_callchain_entry *entry = data;
|
||||
|
||||
while (1) {
|
||||
if (sp < low || sp > high - sizeof(*sf))
|
||||
return sp;
|
||||
sf = (struct stack_frame *) sp;
|
||||
perf_callchain_store(entry, sf->gprs[8]);
|
||||
/* Follow the backchain. */
|
||||
while (1) {
|
||||
low = sp;
|
||||
sp = sf->back_chain;
|
||||
if (!sp)
|
||||
break;
|
||||
if (sp <= low || sp > high - sizeof(*sf))
|
||||
return sp;
|
||||
sf = (struct stack_frame *) sp;
|
||||
perf_callchain_store(entry, sf->gprs[8]);
|
||||
}
|
||||
/* 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;
|
||||
perf_callchain_store(entry, sf->gprs[8]);
|
||||
low = sp;
|
||||
sp = regs->gprs[15];
|
||||
}
|
||||
perf_callchain_store(entry, address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void perf_callchain_kernel(struct perf_callchain_entry *entry,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
unsigned long head, frame_size;
|
||||
struct stack_frame *head_sf;
|
||||
|
||||
if (user_mode(regs))
|
||||
return;
|
||||
|
||||
frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
|
||||
head = regs->gprs[15];
|
||||
head_sf = (struct stack_frame *) head;
|
||||
|
||||
if (!head_sf || !head_sf->back_chain)
|
||||
return;
|
||||
|
||||
head = head_sf->back_chain;
|
||||
head = __store_trace(entry, head,
|
||||
S390_lowcore.async_stack + frame_size - ASYNC_SIZE,
|
||||
S390_lowcore.async_stack + frame_size);
|
||||
|
||||
__store_trace(entry, head, S390_lowcore.thread_info,
|
||||
S390_lowcore.thread_info + THREAD_SIZE);
|
||||
dump_trace(__perf_callchain_kernel, entry, NULL, regs->gprs[15]);
|
||||
}
|
||||
|
||||
/* Perf defintions for PMU event attributes in sysfs */
|
||||
/* Perf definitions for PMU event attributes in sysfs */
|
||||
ssize_t cpumf_events_sysfs_show(struct device *dev,
|
||||
struct device_attribute *attr, char *page)
|
||||
{
|
||||
|
@@ -327,6 +327,7 @@ static void __init setup_lowcore(void)
|
||||
+ PAGE_SIZE - STACK_FRAME_OVERHEAD - sizeof(struct pt_regs);
|
||||
lc->current_task = (unsigned long) init_thread_union.thread_info.task;
|
||||
lc->thread_info = (unsigned long) &init_thread_union;
|
||||
lc->lpp = LPP_MAGIC;
|
||||
lc->machine_flags = S390_lowcore.machine_flags;
|
||||
lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
|
||||
memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
|
||||
@@ -779,6 +780,7 @@ static int __init setup_hwcaps(void)
|
||||
strcpy(elf_platform, "zEC12");
|
||||
break;
|
||||
case 0x2964:
|
||||
case 0x2965:
|
||||
strcpy(elf_platform, "z13");
|
||||
break;
|
||||
}
|
||||
|
@@ -10,78 +10,39 @@
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
static unsigned long save_context_stack(struct stack_trace *trace,
|
||||
unsigned long sp,
|
||||
unsigned long low,
|
||||
unsigned long high,
|
||||
int savesched)
|
||||
static int __save_address(void *data, unsigned long address, int nosched)
|
||||
{
|
||||
struct stack_frame *sf;
|
||||
struct pt_regs *regs;
|
||||
unsigned long addr;
|
||||
struct stack_trace *trace = data;
|
||||
|
||||
while(1) {
|
||||
if (sp < low || sp > high)
|
||||
return sp;
|
||||
sf = (struct stack_frame *)sp;
|
||||
while(1) {
|
||||
addr = sf->gprs[8];
|
||||
if (!trace->skip)
|
||||
trace->entries[trace->nr_entries++] = addr;
|
||||
else
|
||||
trace->skip--;
|
||||
if (trace->nr_entries >= trace->max_entries)
|
||||
return sp;
|
||||
low = sp;
|
||||
sp = sf->back_chain;
|
||||
if (!sp)
|
||||
break;
|
||||
if (sp <= low || sp > high - sizeof(*sf))
|
||||
return sp;
|
||||
sf = (struct stack_frame *)sp;
|
||||
}
|
||||
/* 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;
|
||||
addr = regs->psw.addr;
|
||||
if (savesched || !in_sched_functions(addr)) {
|
||||
if (!trace->skip)
|
||||
trace->entries[trace->nr_entries++] = addr;
|
||||
else
|
||||
trace->skip--;
|
||||
}
|
||||
if (trace->nr_entries >= trace->max_entries)
|
||||
return sp;
|
||||
low = sp;
|
||||
sp = regs->gprs[15];
|
||||
if (nosched && in_sched_functions(address))
|
||||
return 0;
|
||||
if (trace->skip > 0) {
|
||||
trace->skip--;
|
||||
return 0;
|
||||
}
|
||||
if (trace->nr_entries < trace->max_entries) {
|
||||
trace->entries[trace->nr_entries++] = address;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void __save_stack_trace(struct stack_trace *trace, unsigned long sp)
|
||||
static int save_address(void *data, unsigned long address)
|
||||
{
|
||||
unsigned long new_sp, frame_size;
|
||||
return __save_address(data, address, 0);
|
||||
}
|
||||
|
||||
frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
|
||||
new_sp = save_context_stack(trace, sp,
|
||||
S390_lowcore.panic_stack + frame_size - PAGE_SIZE,
|
||||
S390_lowcore.panic_stack + frame_size, 1);
|
||||
new_sp = save_context_stack(trace, new_sp,
|
||||
S390_lowcore.async_stack + frame_size - ASYNC_SIZE,
|
||||
S390_lowcore.async_stack + frame_size, 1);
|
||||
save_context_stack(trace, new_sp,
|
||||
S390_lowcore.thread_info,
|
||||
S390_lowcore.thread_info + THREAD_SIZE, 1);
|
||||
static int save_address_nosched(void *data, unsigned long address)
|
||||
{
|
||||
return __save_address(data, address, 1);
|
||||
}
|
||||
|
||||
void save_stack_trace(struct stack_trace *trace)
|
||||
{
|
||||
register unsigned long r15 asm ("15");
|
||||
unsigned long sp;
|
||||
|
||||
sp = r15;
|
||||
__save_stack_trace(trace, sp);
|
||||
sp = current_stack_pointer();
|
||||
dump_trace(save_address, trace, NULL, sp);
|
||||
if (trace->nr_entries < trace->max_entries)
|
||||
trace->entries[trace->nr_entries++] = ULONG_MAX;
|
||||
}
|
||||
@@ -89,16 +50,12 @@ EXPORT_SYMBOL_GPL(save_stack_trace);
|
||||
|
||||
void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
|
||||
{
|
||||
unsigned long sp, low, high;
|
||||
unsigned long sp;
|
||||
|
||||
sp = tsk->thread.ksp;
|
||||
if (tsk == current) {
|
||||
/* Get current stack pointer. */
|
||||
asm volatile("la %0,0(15)" : "=a" (sp));
|
||||
}
|
||||
low = (unsigned long) task_stack_page(tsk);
|
||||
high = (unsigned long) task_pt_regs(tsk);
|
||||
save_context_stack(trace, sp, low, high, 0);
|
||||
if (tsk == current)
|
||||
sp = current_stack_pointer();
|
||||
dump_trace(save_address_nosched, trace, tsk, sp);
|
||||
if (trace->nr_entries < trace->max_entries)
|
||||
trace->entries[trace->nr_entries++] = ULONG_MAX;
|
||||
}
|
||||
@@ -109,7 +66,7 @@ void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace)
|
||||
unsigned long sp;
|
||||
|
||||
sp = kernel_stack_pointer(regs);
|
||||
__save_stack_trace(trace, sp);
|
||||
dump_trace(save_address, trace, NULL, sp);
|
||||
if (trace->nr_entries < trace->max_entries)
|
||||
trace->entries[trace->nr_entries++] = ULONG_MAX;
|
||||
}
|
||||
|
@@ -499,8 +499,7 @@ static void etr_reset(void)
|
||||
if (etr_port0_online && etr_port1_online)
|
||||
set_bit(CLOCK_SYNC_ETR, &clock_sync_flags);
|
||||
} else if (etr_port0_online || etr_port1_online) {
|
||||
pr_warning("The real or virtual hardware system does "
|
||||
"not provide an ETR interface\n");
|
||||
pr_warn("The real or virtual hardware system does not provide an ETR interface\n");
|
||||
etr_port0_online = etr_port1_online = 0;
|
||||
}
|
||||
}
|
||||
@@ -1464,8 +1463,7 @@ static void __init stp_reset(void)
|
||||
if (rc == 0)
|
||||
set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags);
|
||||
else if (stp_online) {
|
||||
pr_warning("The real or virtual hardware system does "
|
||||
"not provide an STP interface\n");
|
||||
pr_warn("The real or virtual hardware system does not provide an STP interface\n");
|
||||
free_page((unsigned long) stp_page);
|
||||
stp_page = NULL;
|
||||
stp_online = 0;
|
||||
|
@@ -22,8 +22,6 @@
|
||||
#include <asm/fpu/api.h>
|
||||
#include "entry.h"
|
||||
|
||||
int show_unhandled_signals = 1;
|
||||
|
||||
static inline void __user *get_trap_ip(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long address;
|
||||
@@ -35,21 +33,6 @@ static inline void __user *get_trap_ip(struct pt_regs *regs)
|
||||
return (void __user *) (address - (regs->int_code >> 16));
|
||||
}
|
||||
|
||||
static inline void report_user_fault(struct pt_regs *regs, int signr)
|
||||
{
|
||||
if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
|
||||
return;
|
||||
if (!unhandled_signal(current, signr))
|
||||
return;
|
||||
if (!printk_ratelimit())
|
||||
return;
|
||||
printk("User process fault: interruption code %04x ilc:%d ",
|
||||
regs->int_code & 0xffff, regs->int_code >> 17);
|
||||
print_vma_addr("in ", regs->psw.addr);
|
||||
printk("\n");
|
||||
show_regs(regs);
|
||||
}
|
||||
|
||||
int is_valid_bugaddr(unsigned long addr)
|
||||
{
|
||||
return 1;
|
||||
@@ -65,7 +48,7 @@ void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
|
||||
info.si_code = si_code;
|
||||
info.si_addr = get_trap_ip(regs);
|
||||
force_sig_info(si_signo, &info, current);
|
||||
report_user_fault(regs, si_signo);
|
||||
report_user_fault(regs, si_signo, 0);
|
||||
} else {
|
||||
const struct exception_table_entry *fixup;
|
||||
fixup = search_exception_tables(regs->psw.addr);
|
||||
@@ -111,7 +94,7 @@ NOKPROBE_SYMBOL(do_per_trap);
|
||||
void default_trap_handler(struct pt_regs *regs)
|
||||
{
|
||||
if (user_mode(regs)) {
|
||||
report_user_fault(regs, SIGSEGV);
|
||||
report_user_fault(regs, SIGSEGV, 0);
|
||||
do_exit(SIGSEGV);
|
||||
} else
|
||||
die(regs, "Unknown program exception");
|
||||
|
Reference in New Issue
Block a user