Commit b3819ec5 authored by Linus Torvalds's avatar Linus Torvalds

Merge s390 update into current tree

parents 7ac4f06b 5cc974f5
......@@ -123,9 +123,6 @@ Command line parameters
* /proc/chpids
This entry will only show up if you specified CONFIG_CHSC=y during kernel
config.
This entry serves a dual purpose:
- show which chpids are currently known to Linux and their status (online,
......
......@@ -160,25 +160,11 @@ CONFIG_IPL_TAPE
Select "vm_reader" if you are running under VM/ESA and want
to IPL the image from the emulated card reader.
CONFIG_FAST_IRQ
Select this option in order to get the interrupts processed faster
on your S/390 or zSeries machine. If selected, after an interrupt
is processed, the channel subsystem will be asked for other pending
interrupts which will also be processed before leaving the interrupt
context. This speeds up the I/O a lot. Say "Y".
CONFIG_MACHCHK_WARNING
Select this option if you want the machine check handler on IBM S/390 or
zSeries to process warning machine checks (e.g. on power failures).
If unsure, say "Y".
CONFIG_CHSC
Select this option if you want the s390 common I/O layer to use information
obtained by channel subsystem calls. This will enable Linux to process link
failures and resource accessibility events. Moreover, if you have procfs
enabled, you'll be able to toggle chpids logically offline and online. Even
if you don't understand what this means, you should say "Y".
CONFIG_PROCESS_DEBUG
Say Y to print all process fault locations to the console. This is
a debugging option; you probably do not want to set it unless you
......
......@@ -17,22 +17,20 @@ define_bool CONFIG_ARCH_S390 y
source init/Config.in
mainmenu_option next_comment
comment 'Base setup'
comment 'Processor type and features'
bool 'Symmetric multi-processing support' CONFIG_SMP
bool 'IEEE FPU emulation' CONFIG_MATHEMU
endmenu
mainmenu_option next_comment
comment 'Base setup'
bool 'Fast IRQ handling' CONFIG_FAST_IRQ
comment 'I/O subsystem configuration'
bool 'Process warning machine checks' CONFIG_MACHCHK_WARNING
bool 'Use chscs for Common I/O' CONFIG_CHSC
tristate 'QDIO support' CONFIG_QDIO
if [ "$CONFIG_QDIO" != "n" ]; then
bool ' Performance statistics in /proc' CONFIG_QDIO_PERF_STATS
fi
if [ "$CONFIG_QDIO" != "n" ]; then
bool ' Performance statistics in /proc' CONFIG_QDIO_PERF_STATS
fi
comment 'Misc'
bool 'Preemptible Kernel' CONFIG_PREEMPT
bool 'Builtin IPL record support' CONFIG_IPL
if [ "$CONFIG_IPL" = "y" ]; then
choice 'IPL method generated into head.S' \
......@@ -68,7 +66,6 @@ source fs/Config.in
mainmenu_option next_comment
comment 'Kernel hacking'
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
#if [ "$CONFIG_CTC" = "y" ]; then
# bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
#fi
......
......@@ -30,6 +30,10 @@ CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
CONFIG_KMOD=y
#
# Base setup
#
#
# Processor type and features
#
......@@ -37,13 +41,16 @@ CONFIG_SMP=y
CONFIG_MATHEMU=y
#
# Base setup
# I/O subsystem configuration
#
CONFIG_FAST_IRQ=y
CONFIG_MACHCHK_WARNING=y
CONFIG_CHSC=y
CONFIG_QDIO=m
# CONFIG_QDIO_PERF_STATS is not set
#
# Misc
#
# CONFIG_PREEMPT is not set
CONFIG_IPL=y
# CONFIG_IPL_TAPE is not set
CONFIG_IPL_VM=y
......@@ -84,9 +91,6 @@ CONFIG_SCSI_LOGGING=y
#
# CONFIG_SCSI_7000FASST is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_DPT_I2O is not set
......@@ -114,7 +118,6 @@ CONFIG_SCSI_LOGGING=y
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_SIM710 is not set
# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
......@@ -153,7 +156,7 @@ CONFIG_MD_RAID0=m
CONFIG_MD_RAID1=m
CONFIG_MD_RAID5=m
# CONFIG_MD_MULTIPATH is not set
CONFIG_BLK_DEV_LVM=m
# CONFIG_BLK_DEV_LVM is not set
#
# Character device drivers
......@@ -226,25 +229,22 @@ CONFIG_IP_MULTICAST=y
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
CONFIG_IPV6=m
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
# CONFIG_VLAN_8021Q is not set
#
#
# SCTP Configuration (EXPERIMENTAL)
#
CONFIG_IPV6_SCTP__=m
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_LLC is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
#
# Appletalk devices
#
# CONFIG_DEV_APPLETALK is not set
# CONFIG_DECNET is not set
# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
......@@ -299,7 +299,7 @@ CONFIG_RAMFS=y
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
CONFIG_DEVFS_FS=y
CONFIG_DEVFS_MOUNT=y
# CONFIG_DEVFS_MOUNT is not set
# CONFIG_DEVFS_DEBUG is not set
# CONFIG_DEVPTS_FS is not set
# CONFIG_QNX4FS_FS is not set
......@@ -311,6 +311,9 @@ CONFIG_EXT2_FS=y
# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
# CONFIG_UFS_FS_WRITE is not set
# CONFIG_XFS_FS is not set
# CONFIG_XFS_RT is not set
# CONFIG_XFS_QUOTA is not set
#
# Network File Systems
......@@ -362,6 +365,11 @@ CONFIG_IBM_PARTITION=y
#
CONFIG_MAGIC_SYSRQ=y
#
# Security options
#
CONFIG_SECURITY_CAPABILITIES=y
#
# Library routines
#
......
......@@ -5,10 +5,10 @@
EXTRA_TARGETS := head.o init_task.o
EXTRA_AFLAGS := -traditional
export-objs := debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o
obj-y := entry.o bitmap.o traps.o time.o process.o irq.o \
export-objs := debug.o ebcdic.o s390_ext.o smp.o s390_ksyms.o
obj-y := entry.o bitmap.o traps.o time.o process.o \
setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
semaphore.o s390fpu.o reipl.o s390_ext.o debug.o
semaphore.o reipl.o s390_ext.o debug.o
obj-$(CONFIG_MODULES) += s390_ksyms.o
obj-$(CONFIG_SMP) += smp.o
......
......@@ -21,6 +21,7 @@
#include <asm/semaphore.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/debug.h>
......@@ -146,7 +147,7 @@ static debug_info_t *debug_area_first = NULL;
static debug_info_t *debug_area_last = NULL;
DECLARE_MUTEX(debug_lock);
static int initialized = 0;
static int initialized;
static struct file_operations debug_file_ops = {
read: debug_output,
......@@ -591,7 +592,7 @@ debug_info_t *debug_register
MOD_INC_USE_COUNT;
if (!initialized)
debug_init();
BUG();
down(&debug_lock);
/* create new debug_info */
......@@ -828,18 +829,16 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id,
* - is called exactly once to initialize the debug feature
*/
int debug_init(void)
static int __init debug_init(void)
{
int rc = 0;
down(&debug_lock);
if (!initialized) {
#ifdef CONFIG_PROC_FS
debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
#endif /* CONFIG_PROC_FS */
printk(KERN_INFO "debug: Initialization complete\n");
initialized = 1;
}
printk(KERN_INFO "debug: Initialization complete\n");
initialized = 1;
up(&debug_lock);
return rc;
......@@ -1173,27 +1172,9 @@ int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
}
/*
* init_module:
*/
#ifdef MODULE
int init_module(void)
{
int rc = 0;
#ifdef DEBUG
printk("debug_module_init: \n");
#endif
rc = debug_init();
if (rc)
printk(KERN_INFO "debug: an error occurred with debug_init\n");
return rc;
}
/*
* cleanup_module:
* clean up module
*/
void cleanup_module(void)
void __exit debug_exit(void)
{
#ifdef DEBUG
printk("debug_cleanup_module: \n");
......@@ -1204,7 +1185,12 @@ void cleanup_module(void)
return;
}
#endif /* MODULE */
/*
* module definitions
*/
core_initcall(debug_init);
module_exit(debug_exit);
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(debug_register);
EXPORT_SYMBOL(debug_unregister);
......
This diff is collapsed.
......@@ -653,5 +653,5 @@ _stext: basr %r13,0 # get base
.Lstart: .long start_kernel
.Lbss_bgn: .long __bss_start
.Lbss_end: .long _end
.Laregs: .long 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
.Laregs: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
......@@ -15,7 +15,7 @@
static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
struct mm_struct init_mm = INIT_MM(init_mm);
/*
......
/*
* arch/s390/kernel/irq.c
*
* S390 version
* Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Ingo Adlung (adlung@de.ibm.com)
*
* Derived from "arch/i386/kernel/irq.c"
* Copyright (C) 1992, 1999 Linus Torvalds, Ingo Molnar
*
* S/390 I/O interrupt processing and I/O request processing is
* implemented in arch/s390/kernel/s390io.c
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/random.h>
#include <linux/smp.h>
#include <linux/threads.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/seq_file.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/smp.h>
#include <asm/pgtable.h>
#include <asm/delay.h>
#include <asm/lowcore.h>
void s390_init_IRQ ( void );
void s390_free_irq ( unsigned int irq, void *dev_id);
int s390_request_irq( unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id);
#if 0
/*
* The following vectors are part of the Linux architecture, there
* is no hardware IRQ pin equivalent for them, they are triggered
* through the ICC by us (IPIs), via smp_message_pass():
*/
BUILD_SMP_INTERRUPT(reschedule_interrupt)
BUILD_SMP_INTERRUPT(invalidate_interrupt)
BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
BUILD_SMP_INTERRUPT(mtrr_interrupt)
BUILD_SMP_INTERRUPT(spurious_interrupt)
#endif
int show_interrupts(struct seq_file *p, void *v)
{
int i, j;
seq_puts(p, " ");
for (j=0; j<smp_num_cpus; j++)
seq_printf(p, "CPU%d ",j);
seq_putc(p, '\n');
for (i = 0 ; i < NR_IRQS ; i++) {
if (ioinfo[i] == INVALID_STORAGE_AREA)
continue;
seq_printf(p, "%3d: ",i);
seq_printf(p, " %s", ioinfo[i]->irq_desc.name);
seq_putc(p, '\n');
} /* endfor */
return 0;
}
/*
* Global interrupt locks for SMP. Allow interrupts to come in on any
* CPU, yet make cli/sti act globally to protect critical regions..
*/
#ifdef CONFIG_SMP
atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID);
atomic_t global_irq_lock = ATOMIC_INIT(0);
atomic_t global_irq_count = ATOMIC_INIT(0);
atomic_t global_bh_count;
/*
* "global_cli()" is a special case, in that it can hold the
* interrupts disabled for a longish time, and also because
* we may be doing TLB invalidates when holding the global
* IRQ lock for historical reasons. Thus we may need to check
* SMP invalidate events specially by hand here (but not in
* any normal spinlocks)
*
* Thankfully we don't need this as we can deliver flush tlbs with
* interrupts disabled DJB :-)
*/
#define check_smp_invalidate(cpu)
extern void show_stack(unsigned long* esp);
static void show(char * str)
{
int cpu = smp_processor_id();
printk("\n%s, CPU %d:\n", str, cpu);
printk("irq: %d [%d]\n",
atomic_read(&global_irq_count),local_irq_count(smp_processor_id()));
printk("bh: %d [%d]\n",
atomic_read(&global_bh_count),local_bh_count(smp_processor_id()));
show_stack(NULL);
}
#define MAXCOUNT 100000000
static inline void wait_on_bh(void)
{
int count = MAXCOUNT;
do {
if (!--count) {
show("wait_on_bh");
count = ~0;
}
/* nothing .. wait for the other bh's to go away */
} while (atomic_read(&global_bh_count) != 0);
}
static inline void wait_on_irq(int cpu)
{
int count = MAXCOUNT;
for (;;) {
/*
* Wait until all interrupts are gone. Wait
* for bottom half handlers unless we're
* already executing in one..
*/
if (!atomic_read(&global_irq_count)) {
if (local_bh_count(cpu)||
!atomic_read(&global_bh_count))
break;
}
/* Duh, we have to loop. Release the lock to avoid deadlocks */
atomic_set(&global_irq_lock, 0);
for (;;) {
if (!--count) {
show("wait_on_irq");
count = ~0;
}
local_irq_enable();
SYNC_OTHER_CORES(cpu);
local_irq_disable();
check_smp_invalidate(cpu);
if (atomic_read(&global_irq_count))
continue;
if (atomic_read(&global_irq_lock))
continue;
if (!local_bh_count(cpu)
&& atomic_read(&global_bh_count))
continue;
if (!atomic_compare_and_swap(0, 1, &global_irq_lock))
break;
}
}
}
/*
* This is called when we want to synchronize with
* bottom half handlers. We need to wait until
* no other CPU is executing any bottom half handler.
*
* Don't wait if we're already running in an interrupt
* context or are inside a bh handler.
*/
void synchronize_bh(void)
{
if (atomic_read(&global_bh_count) && !in_interrupt())
wait_on_bh();
}
/*
* This is called when we want to synchronize with
* interrupts. We may for example tell a device to
* stop sending interrupts: but to make sure there
* are no interrupts that are executing on another
* CPU we need to call this function.
*/
void synchronize_irq(void)
{
if (atomic_read(&global_irq_count)) {
/* Stupid approach */
cli();
sti();
}
}
static inline void get_irqlock(int cpu)
{
if (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0) {
/* do we already hold the lock? */
if ( cpu == atomic_read(&global_irq_holder))
return;
/* Uhhuh.. Somebody else got it. Wait.. */
do {
check_smp_invalidate(cpu);
} while (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0);
}
/*
* We also to make sure that nobody else is running
* in an interrupt context.
*/
wait_on_irq(cpu);
/*
* Ok, finally..
*/
atomic_set(&global_irq_holder,cpu);
}
#define EFLAGS_I_SHIFT 25
/*
* A global "cli()" while in an interrupt context
* turns into just a local cli(). Interrupts
* should use spinlocks for the (very unlikely)
* case that they ever want to protect against
* each other.
*
* If we already have local interrupts disabled,
* this will not turn a local disable into a
* global one (problems with spinlocks: this makes
* save_flags+cli+sti usable inside a spinlock).
*/
void __global_cli(void)
{
unsigned long flags;
local_save_flags(flags);
if (flags & (1 << EFLAGS_I_SHIFT)) {
int cpu = smp_processor_id();
local_irq_disable();
if (!in_irq())
get_irqlock(cpu);
}
}
void __global_sti(void)
{
if (!in_irq())
release_irqlock(smp_processor_id());
local_irq_enable();
}
/*
* SMP flags value to restore to:
* 0 - global cli
* 1 - global sti
* 2 - local cli
* 3 - local sti
*/
unsigned long __global_save_flags(void)
{
int retval;
int local_enabled;
unsigned long flags;
local_save_flags(flags);
local_enabled = (flags >> EFLAGS_I_SHIFT) & 1;
/* default to local */
retval = 2 + local_enabled;
/* check for global flags if we're not in an interrupt */
if (!in_irq())
{
if (local_enabled)
retval = 1;
if (atomic_read(&global_irq_holder)== smp_processor_id())
retval = 0;
}
return retval;
}
void __global_restore_flags(unsigned long flags)
{
switch (flags) {
case 0:
__global_cli();
break;
case 1:
__global_sti();
break;
case 2:
local_irq_disable();
break;
case 3:
local_irq_enable();
break;
default:
printk("global_restore_flags: %08lx (%08lx)\n",
flags, (&flags)[-1]);
}
}
#endif
void __init init_IRQ(void)
{
s390_init_IRQ();
}
void free_irq(unsigned int irq, void *dev_id)
{
s390_free_irq( irq, dev_id);
}
int request_irq( unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id)
{
return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) );
}
void init_irq_proc(void)
{
/* For now, nothing... */
}
#ifdef CONFIG_SMP
EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
EXPORT_SYMBOL(global_irq_holder);
EXPORT_SYMBOL(global_irq_lock);
EXPORT_SYMBOL(global_irq_count);
EXPORT_SYMBOL(global_bh_count);
#endif
EXPORT_SYMBOL(global_bh_lock);
......@@ -15,9 +15,6 @@
* This file handles the architecture-dependent parts of process handling..
*/
#define __KERNEL_SYSCALLS__
#include <stdarg.h>
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
......@@ -78,9 +75,10 @@ void default_idle(void)
/*
* Wait for external, I/O or machine check interrupt and
* switch of machine check bit after the wait has ended.
* switch off machine check bit after the wait has ended.
*/
wait_psw.mask = _WAIT_PSW_MASK;
wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT |
PSW_MASK_IO | PSW_MASK_EXT;
asm volatile (
" basr %0,0\n"
"0: la %0,1f-0b(%0)\n"
......@@ -117,35 +115,39 @@ void show_regs(struct pt_regs *regs)
show_registers(regs);
/* Show stack backtrace if pt_regs is from kernel mode */
if (!(regs->psw.mask & PSW_PROBLEM_STATE))
if (!(regs->psw.mask & PSW_MASK_PSTATE))
show_trace((unsigned long *) regs->gprs[15]);
}
extern void kernel_thread_starter(void);
__asm__(".align 4\n"
"kernel_thread_starter:\n"
" l 15,0(8)\n"
" sr 15,7\n"
" stosm 24(15),3\n"
" lr 2,10\n"
" basr 14,9\n"
" sr 2,2\n"
" br 11\n");
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
int clone_arg = flags | CLONE_VM;
int retval;
__asm__ __volatile__(
" sr 2,2\n"
" lr 3,%1\n"
" l 4,%6\n" /* load kernel stack ptr of parent */
" svc %b2\n" /* Linux system call*/
" cl 4,%6\n" /* compare ksp's: child or parent ? */
" je 0f\n" /* parent - jump*/
" l 15,%6\n" /* fix kernel stack pointer*/
" ahi 15,%7\n"
" xc 0(96,15),0(15)\n" /* clear save area */
" lr 2,%4\n" /* load argument*/
" lr 14,%5\n" /* get fn-pointer*/
" basr 14,14\n" /* call fn*/
" svc %b3\n" /* Linux system call*/
"0: lr %0,2"
: "=a" (retval)
: "d" (clone_arg), "i" (__NR_clone), "i" (__NR_exit),
"d" (arg), "d" (fn), "i" (__LC_KERNEL_STACK) , "i" (-STACK_FRAME_OVERHEAD)
: "2", "3", "4" );
return retval;
struct task_struct *p;
struct pt_regs regs;
memset(&regs, 0, sizeof(regs));
regs.psw.mask = PSW_KERNEL_BITS;
regs.psw.addr = (__u32) kernel_thread_starter | PSW_ADDR_AMODE31;
regs.gprs[7] = STACK_FRAME_OVERHEAD;
regs.gprs[8] = __LC_KERNEL_STACK;
regs.gprs[9] = (unsigned long) fn;
regs.gprs[10] = (unsigned long) arg;
regs.gprs[11] = (unsigned long) do_exit;
regs.orig_gpr2 = -1;
/* Ok, create the new process.. */
p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
/*
......@@ -186,20 +188,28 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
frame = ((struct stack_frame *)
(THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
p->thread.ksp = (unsigned long) frame;
memcpy(&frame->childregs,regs,sizeof(struct pt_regs));
frame->childregs = *regs;
frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */
frame->childregs.gprs[15] = new_stackp;
frame->back_chain = frame->eos = 0;
/* new return point is ret_from_sys_call */
frame->gprs[8] = ((unsigned long) &ret_from_fork) | 0x80000000;
/* new return point is ret_from_fork */
frame->gprs[8] = (unsigned long) ret_from_fork;
/* start disabled because of schedule_tick and rq->lock being held */
frame->childregs.psw.mask &= ~0x03000000;
/* fake return stack for resume(), don't go back to schedule */
frame->gprs[9] = (unsigned long) frame;
/* save fprs, if used in last task */
save_fp_regs(&p->thread.fp_regs);
/*
* save fprs to current->thread.fp_regs to merge them with
* the emulated registers and then copy the result to the child.
*/
save_fp_regs(&current->thread.fp_regs);
memcpy(&p->thread.fp_regs, &current->thread.fp_regs,
sizeof(s390_fp_regs));
p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _SEGMENT_TABLE;
/* start process with ar4 pointing to the correct address space */
p->thread.ar4 = get_fs().ar4;
/* Don't copy debug registers */
memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
return 0;
......@@ -208,7 +218,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
asmlinkage int sys_fork(struct pt_regs regs)
{
struct task_struct *p;
p = do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
p = do_fork(SIGCHLD, regs.gprs[15], &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......@@ -217,12 +227,14 @@ asmlinkage int sys_clone(struct pt_regs regs)
unsigned long clone_flags;
unsigned long newsp;
struct task_struct *p;
int *user_tid;
clone_flags = regs.gprs[3];
newsp = regs.orig_gpr2;
user_tid = (int *) regs.gprs[4];
if (!newsp)
newsp = regs.gprs[15];
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0);
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, user_tid);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......@@ -239,7 +251,8 @@ asmlinkage int sys_clone(struct pt_regs regs)
asmlinkage int sys_vfork(struct pt_regs regs)
{
struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.gprs[15], &regs, 0);
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
regs.gprs[15], &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......@@ -255,20 +268,13 @@ asmlinkage int sys_execve(struct pt_regs regs)
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], &regs);
if (error == 0)
{
error = do_execve(filename, (char **) regs.gprs[3],
(char **) regs.gprs[4], &regs);
if (error == 0) {
current->ptrace &= ~PT_DTRACE;
current->thread.fp_regs.fpc=0;
if(MACHINE_HAS_IEEE)
{
__asm__ __volatile__
("sr 0,0\n\t"
"sfpc 0,0\n\t"
:
:
:"0");
}
current->thread.fp_regs.fpc = 0;
if (MACHINE_HAS_IEEE)
asm volatile("sfpc %0,%0" : : "d" (0));
}
putname(filename);
out:
......@@ -281,7 +287,12 @@ asmlinkage int sys_execve(struct pt_regs regs)
*/
int dump_fpu (struct pt_regs * regs, s390_fp_regs *fpregs)
{
save_fp_regs(fpregs);
/*
* save fprs to current->thread.fp_regs to merge them with
* the emulated registers and then copy the result to the dump.
*/
save_fp_regs(&current->thread.fp_regs);
memcpy(fpregs, &current->thread.fp_regs, sizeof(s390_fp_regs));
return 1;
}
......@@ -295,15 +306,15 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
dump->magic = CMAGIC;
dump->start_code = 0;
dump->start_stack = regs->gprs[15] & ~(PAGE_SIZE - 1);
dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
dump->u_tsize = current->mm->end_code >> PAGE_SHIFT;
dump->u_dsize = (current->mm->brk + PAGE_SIZE - 1) >> PAGE_SHIFT;
dump->u_dsize -= dump->u_tsize;
dump->u_ssize = 0;
if (dump->start_stack < TASK_SIZE)
dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
memcpy(&dump->regs.gprs[0],regs,sizeof(s390_regs));
dump->u_ssize = (TASK_SIZE - dump->start_stack) >> PAGE_SHIFT;
memcpy(&dump->regs, regs, sizeof(s390_regs));
dump_fpu (regs, &dump->regs.fp_regs);
memcpy(&dump->regs.per_info,&current->thread.per_info,sizeof(per_struct));
dump->regs.per_info = current->thread.per_info;
}
/*
......
This diff is collapsed.
/*
* arch/s390/kernel/s390fpu.c
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
*
* s390fpu.h functions for saving & restoring the fpu state.
*
* I couldn't inline these as linux/sched.h included half the world
* & was required to at the task structure.
* & the functions were too complex to make macros from.
* ( & as usual I didn't feel like debugging inline code ).
*/
#include <linux/config.h>
#include <linux/sched.h>
int save_fp_regs1(s390_fp_regs *fpregs)
{
int has_ieee=MACHINE_HAS_IEEE;
/*
I don't think we can use STE here as this would load
fp registers 0 & 2 into memory locations 0 & 1 etc.
*/
asm volatile ("STD 0,8(%0)\n\t"
"STD 2,24(%0)\n\t"
"STD 4,40(%0)\n\t"
"STD 6,56(%0)"
:
: "a" (fpregs)
: "memory"
);
if(has_ieee)
{
asm volatile ("STFPC 0(%0)\n\t"
"STD 1,16(%0)\n\t"
"STD 3,32(%0)\n\t"
"STD 5,48(%0)\n\t"
"STD 7,64(%0)\n\t"
"STD 8,72(%0)\n\t"
"STD 9,80(%0)\n\t"
"STD 10,88(%0)\n\t"
"STD 11,96(%0)\n\t"
"STD 12,104(%0)\n\t"
"STD 13,112(%0)\n\t"
"STD 14,120(%0)\n\t"
"STD 15,128(%0)\n\t"
:
: "a" (fpregs)
: "memory"
);
}
return(has_ieee);
}
void save_fp_regs(s390_fp_regs *fpregs)
{
#if CONFIG_MATHEMU
s390_fp_regs *currentfprs;
if(!save_fp_regs1(fpregs))
{
currentfprs=&current->thread.fp_regs;
fpregs->fpc=currentfprs->fpc;
fpregs->fprs[1].d=currentfprs->fprs[1].d;
fpregs->fprs[3].d=currentfprs->fprs[3].d;
fpregs->fprs[5].d=currentfprs->fprs[5].d;
fpregs->fprs[7].d=currentfprs->fprs[7].d;
memcpy(&fpregs->fprs[8].d,&currentfprs->fprs[8].d,sizeof(freg_t)*8);
}
#else
save_fp_regs1(fpregs);
#endif
}
int restore_fp_regs1(s390_fp_regs *fpregs)
{
int has_ieee=MACHINE_HAS_IEEE;
/* If we don't mask with the FPC_VALID_MASK here
* we've got a very quick shutdown -h now command
* via a kernel specification exception.
*/
fpregs->fpc&=FPC_VALID_MASK;
asm volatile ("LD 0,8(%0)\n\t"
"LD 2,24(%0)\n\t"
"LD 4,40(%0)\n\t"
"LD 6,56(%0)"
:
: "a" (fpregs)
: "memory"
);
if(has_ieee)
{
asm volatile ("LFPC 0(%0)\n\t"
"LD 1,16(%0)\n\t"
"LD 3,32(%0)\n\t"
"LD 5,48(%0)\n\t"
"LD 7,64(%0)\n\t"
"LD 8,72(%0)\n\t"
"LD 9,80(%0)\n\t"
"LD 10,88(%0)\n\t"
"LD 11,96(%0)\n\t"
"LD 12,104(%0)\n\t"
"LD 13,112(%0)\n\t"
"LD 14,120(%0)\n\t"
"LD 15,128(%0)\n\t"
:
: "a" (fpregs)
: "memory"
);
}
return(has_ieee);
}
void restore_fp_regs(s390_fp_regs *fpregs)
{
#if CONFIG_MATHEMU
s390_fp_regs *currentfprs;
if(!restore_fp_regs1(fpregs))
{
currentfprs=&current->thread.fp_regs;
currentfprs->fpc=fpregs->fpc;
currentfprs->fprs[1].d=fpregs->fprs[1].d;
currentfprs->fprs[3].d=fpregs->fprs[3].d;
currentfprs->fprs[5].d=fpregs->fprs[5].d;
currentfprs->fprs[7].d=fpregs->fprs[7].d;
memcpy(&currentfprs->fprs[8].d,&fpregs->fprs[8].d,sizeof(freg_t)*8);
}
#else
restore_fp_regs1(fpregs);
#endif
}
......@@ -52,7 +52,6 @@ unsigned long machine_flags = 0;
struct { unsigned long addr, size, type; } memory_chunk[16] = { { 0 } };
#define CHUNK_READ_WRITE 0
#define CHUNK_READ_ONLY 1
__u16 boot_cpu_addr;
int cpus_initialized = 0;
unsigned long cpu_initialized = 0;
volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
......@@ -79,7 +78,7 @@ static struct resource data_resource = { "Kernel data", 0, 0 };
/*
* cpu_init() initializes state that is per-CPU.
*/
void __init cpu_init (void)
void __devinit cpu_init (void)
{
int nr = smp_processor_id();
int addr = hard_smp_processor_id();
......@@ -305,7 +304,7 @@ void __init setup_arch(char **cmdline_p)
unsigned long start_pfn, end_pfn;
static unsigned int smptrap=0;
unsigned long delay = 0;
struct _lowcore *lowcore;
struct _lowcore *lc;
int i;
if (smptrap)
......@@ -452,30 +451,28 @@ void __init setup_arch(char **cmdline_p)
/*
* Setup lowcore for boot cpu
*/
lowcore = (struct _lowcore *)
__alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
memset(lowcore, 0, PAGE_SIZE);
lowcore->restart_psw.mask = _RESTART_PSW_MASK;
lowcore->restart_psw.addr = _ADDR_31 + (addr_t) &restart_int_handler;
lowcore->external_new_psw.mask = _EXT_PSW_MASK;
lowcore->external_new_psw.addr = _ADDR_31 + (addr_t) &ext_int_handler;
lowcore->svc_new_psw.mask = _SVC_PSW_MASK;
lowcore->svc_new_psw.addr = _ADDR_31 + (addr_t) &system_call;
lowcore->program_new_psw.mask = _PGM_PSW_MASK;
lowcore->program_new_psw.addr = _ADDR_31 + (addr_t) &pgm_check_handler;
lowcore->mcck_new_psw.mask = _MCCK_PSW_MASK;
lowcore->mcck_new_psw.addr = _ADDR_31 + (addr_t) &mcck_int_handler;
lowcore->io_new_psw.mask = _IO_PSW_MASK;
lowcore->io_new_psw.addr = _ADDR_31 + (addr_t) &io_int_handler;
lowcore->ipl_device = S390_lowcore.ipl_device;
lowcore->kernel_stack = ((__u32) &init_thread_union) + 8192;
lowcore->async_stack = (__u32)
lc = (struct _lowcore *) __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
memset(lc, 0, PAGE_SIZE);
lc->restart_psw.mask = PSW_BASE_BITS;
lc->restart_psw.addr = PSW_ADDR_AMODE31 + (__u32) restart_int_handler;
lc->external_new_psw.mask = PSW_KERNEL_BITS;
lc->external_new_psw.addr = PSW_ADDR_AMODE31 + (__u32) ext_int_handler;
lc->svc_new_psw.mask = PSW_KERNEL_BITS;
lc->svc_new_psw.addr = PSW_ADDR_AMODE31 + (__u32) system_call;
lc->program_new_psw.mask = PSW_KERNEL_BITS;
lc->program_new_psw.addr = PSW_ADDR_AMODE31 + (__u32)pgm_check_handler;
lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
lc->mcck_new_psw.addr = PSW_ADDR_AMODE31 + (__u32) mcck_int_handler;
lc->io_new_psw.mask = PSW_KERNEL_BITS;
lc->io_new_psw.addr = PSW_ADDR_AMODE31 + (__u32) io_int_handler;
lc->ipl_device = S390_lowcore.ipl_device;
lc->kernel_stack = ((__u32) &init_thread_union) + 8192;
lc->async_stack = (__u32)
__alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0) + 8192;
lowcore->jiffy_timer = -1LL;
set_prefix((__u32) lowcore);
lc->jiffy_timer = -1LL;
set_prefix((__u32) lc);
cpu_init();
boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
__cpu_logical_map[0] = boot_cpu_addr;
__cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
/*
* Create kernel page tables and switch to virtual addressing.
......@@ -524,11 +521,14 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "vendor_id : IBM/S390\n"
"# processors : %i\n"
"bogomips per cpu: %lu.%02lu\n",
smp_num_cpus, loops_per_jiffy/(500000/HZ),
num_online_cpus(), loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ))%100);
}
if (cpu_online_map & (1 << n)) {
cpuinfo = &safe_get_cpu_lowcore(n)->cpu_data;
if (smp_processor_id() == n)
cpuinfo = &S390_lowcore.cpu_data;
else
cpuinfo = &lowcore_ptr[n]->cpu_data;
seq_printf(m, "processor %li: "
"version = %02X, "
"identification = %06X, "
......
......@@ -49,22 +49,23 @@ typedef struct
struct ucontext uc;
} rt_sigframe;
asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset));
int do_signal(struct pt_regs *regs, sigset_t *oldset);
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
asmlinkage int
sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t mask)
sys_sigsuspend(struct pt_regs * regs, int history0, int history1,
old_sigset_t mask)
{
sigset_t saveset;
mask &= _BLOCKABLE;
spin_lock_irq(&current->sigmask_lock);
spin_lock_irq(&current->sig->siglock);
saveset = current->blocked;
siginitset(&current->blocked, mask);
recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock);
spin_unlock_irq(&current->sig->siglock);
regs->gprs[2] = -EINTR;
while (1) {
......@@ -88,11 +89,11 @@ sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize)
return -EFAULT;
sigdelsetmask(&newset, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock);
spin_lock_irq(&current->sig->siglock);
saveset = current->blocked;
current->blocked = newset;
recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock);
spin_unlock_irq(&current->sig->siglock);
regs->gprs[2] = -EINTR;
while (1) {
......@@ -147,37 +148,39 @@ sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs)
static int save_sigregs(struct pt_regs *regs,_sigregs *sregs)
{
int err;
s390_fp_regs fpregs;
err = __copy_to_user(&sregs->regs,regs,sizeof(_s390_regs_common));
if(!err)
{
save_fp_regs(&fpregs);
err=__copy_to_user(&sregs->fpregs,&fpregs,sizeof(fpregs));
}
return(err);
err = __copy_to_user(&sregs->regs, regs, sizeof(_s390_regs_common));
if (err != 0)
return err;
/*
* We have to store the fp registers to current->thread.fp_regs
* to merge them with the emulated registers.
*/
save_fp_regs(&current->thread.fp_regs);
return __copy_to_user(&sregs->fpregs, &current->thread.fp_regs,
sizeof(s390_fp_regs));
}
/* Returns positive number on error */
static int restore_sigregs(struct pt_regs *regs,_sigregs *sregs)
{
int err;
s390_fp_regs fpregs;
psw_t saved_psw=regs->psw;
err=__copy_from_user(regs,&sregs->regs,sizeof(_s390_regs_common));
if(!err)
{
regs->trap = -1; /* disable syscall checks */
regs->psw.mask=(saved_psw.mask&~PSW_MASK_DEBUGCHANGE)|
(regs->psw.mask&PSW_MASK_DEBUGCHANGE);
regs->psw.addr=(saved_psw.addr&~PSW_ADDR_DEBUGCHANGE)|
(regs->psw.addr&PSW_ADDR_DEBUGCHANGE);
err=__copy_from_user(&fpregs,&sregs->fpregs,sizeof(fpregs));
if(!err)
restore_fp_regs(&fpregs);
}
return(err);
err = __copy_from_user(regs, &sregs->regs, sizeof(_s390_regs_common));
regs->psw.mask = PSW_USER_BITS | (regs->psw.mask & PSW_MASK_CC);
regs->psw.addr |= PSW_ADDR_AMODE31;
if (err)
return err;
err = __copy_from_user(&current->thread.fp_regs, &sregs->fpregs,
sizeof(s390_fp_regs));
current->thread.fp_regs.fpc &= FPC_VALID_MASK;
if (err)
return err;
restore_fp_regs(&current->thread.fp_regs);
regs->trap = -1; /* disable syscall checks */
return 0;
}
asmlinkage long sys_sigreturn(struct pt_regs *regs)
......@@ -191,10 +194,10 @@ asmlinkage long sys_sigreturn(struct pt_regs *regs)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock);
spin_lock_irq(&current->sig->siglock);
current->blocked = set;
recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock);
spin_unlock_irq(&current->sig->siglock);
if (restore_sigregs(regs, &frame->sregs))
goto badframe;
......@@ -217,10 +220,10 @@ asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
goto badframe;
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock);
spin_lock_irq(&current->sig->siglock);
current->blocked = set;
recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock);
spin_unlock_irq(&current->sig->siglock);
if (restore_sigregs(regs, &frame->uc.uc_mcontext))
goto badframe;
......@@ -295,9 +298,9 @@ static void setup_frame(int sig, struct k_sigaction *ka,
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) {
regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
regs->gprs[14] = (__u32) ka->sa.sa_restorer | PSW_ADDR_AMODE31;
} else {
regs->gprs[14] = FIX_PSW(frame->retcode);
regs->gprs[14] = (__u32) frame->retcode | PSW_ADDR_AMODE31;
if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
(u16 *)(frame->retcode)))
goto give_sigsegv;
......@@ -308,12 +311,12 @@ static void setup_frame(int sig, struct k_sigaction *ka,
goto give_sigsegv;
/* Set up registers for signal handler */
regs->gprs[15] = (addr_t)frame;
regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
regs->psw.mask = _USER_PSW_MASK;
regs->gprs[15] = (__u32) frame;
regs->psw.addr = (__u32) ka->sa.sa_handler | PSW_ADDR_AMODE31;
regs->psw.mask = PSW_USER_BITS;
regs->gprs[2] = map_signal(sig);
regs->gprs[3] = (addr_t)&frame->sc;
regs->gprs[3] = (__u32) &frame->sc;
/* We forgot to include these in the sigcontext.
To avoid breaking binary compatibility, they are passed as args. */
......@@ -353,9 +356,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) {
regs->gprs[14] = FIX_PSW(ka->sa.sa_restorer);
regs->gprs[14] = (__u32) ka->sa.sa_restorer | PSW_ADDR_AMODE31;
} else {
regs->gprs[14] = FIX_PSW(frame->retcode);
regs->gprs[14] = (__u32) frame->retcode | PSW_ADDR_AMODE31;
err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
(u16 *)(frame->retcode));
}
......@@ -365,13 +368,13 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
goto give_sigsegv;
/* Set up registers for signal handler */
regs->gprs[15] = (addr_t)frame;
regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
regs->psw.mask = _USER_PSW_MASK;
regs->gprs[15] = (__u32) frame;
regs->psw.addr = (__u32) ka->sa.sa_handler | PSW_ADDR_AMODE31;
regs->psw.mask = PSW_USER_BITS;
regs->gprs[2] = map_signal(sig);
regs->gprs[3] = (addr_t)&frame->info;
regs->gprs[4] = (addr_t)&frame->uc;
regs->gprs[3] = (__u32) &frame->info;
regs->gprs[4] = (__u32) &frame->uc;
return;
give_sigsegv:
......@@ -420,11 +423,11 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
ka->sa.sa_handler = SIG_DFL;
if (!(ka->sa.sa_flags & SA_NODEFER)) {
spin_lock_irq(&current->sigmask_lock);
spin_lock_irq(&current->sig->siglock);
sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
sigaddset(&current->blocked,sig);
recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock);
spin_unlock_irq(&current->sig->siglock);
}
}
......
This diff is collapsed.
......@@ -27,6 +27,7 @@
#include <asm/uaccess.h>
#include <asm/delay.h>
#include <asm/s390_ext.h>
#include <asm/div64.h>
#include <linux/timex.h>
#include <linux/config.h>
......@@ -37,55 +38,39 @@
#define USECS_PER_JIFFY ((unsigned long) 1000000/HZ)
#define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
/*
* Create a small time difference between the timer interrupts
* on the different cpus to avoid lock contention.
*/
#define CPU_DEVIATION (smp_processor_id() << 12)
#define TICK_SIZE tick
u64 jiffies_64;
static ext_int_info_t ext_int_info_timer;
static uint64_t xtime_cc;
static uint64_t init_timer_cc;
extern rwlock_t xtime_lock;
extern unsigned long wall_jiffies;
void tod_to_timeval(__u64 todval, struct timeval *xtime)
void tod_to_timeval(__u64 todval, struct timespec *xtime)
{
const int high_bit = 0x80000000L;
const int c_f4240 = 0xf4240L;
const int c_7a120 = 0x7a120;
/* We have to divide the 64 bit value todval by 4096
* (because the 2^12 bit is the one that changes every
* microsecond) and then split it into seconds and
* microseconds. A value of max (2^52-1) divided by
* the value 0xF4240 can yield a max result of approx
* (2^32.068). Thats to big to fit into a signed int
* ... hacking time!
*/
asm volatile ("L 2,%1\n\t"
"LR 3,2\n\t"
"SRL 2,12\n\t"
"SLL 3,20\n\t"
"L 4,%O1+4(%R1)\n\t"
"SRL 4,12\n\t"
"OR 3,4\n\t" /* now R2/R3 contain (todval >> 12) */
"SR 4,4\n\t"
"CL 2,%2\n\t"
"JL .+12\n\t"
"S 2,%2\n\t"
"L 4,%3\n\t"
"D 2,%4\n\t"
"OR 3,4\n\t"
"ST 2,%O0+4(%R0)\n\t"
"ST 3,%0"
: "=m" (*xtime) : "m" (todval),
"m" (c_7a120), "m" (high_bit), "m" (c_f4240)
: "cc", "memory", "2", "3", "4" );
unsigned long long sec;
sec = todval >> 12;
do_div(sec, 1000000);
xtime->tv_sec = sec;
todval -= (sec * 1000000) << 12;
xtime->tv_nsec = ((todval * 1000) >> 12);
}
static inline unsigned long do_gettimeoffset(void)
{
__u64 now;
asm ("STCK 0(%0)" : : "a" (&now) : "memory", "cc");
asm volatile ("STCK 0(%0)" : : "a" (&now) : "memory", "cc");
now = (now - init_timer_cc) >> 12;
/* We require the offset from the latest update of xtime */
now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
......@@ -102,7 +87,7 @@ void do_gettimeofday(struct timeval *tv)
read_lock_irqsave(&xtime_lock, flags);
sec = xtime.tv_sec;
usec = xtime.tv_usec + do_gettimeoffset();
usec = xtime.tv_nsec / 1000 + do_gettimeoffset();
read_unlock_irqrestore(&xtime_lock, flags);
while (usec >= 1000000) {
......@@ -118,7 +103,7 @@ void do_settimeofday(struct timeval *tv)
{
write_lock_irq(&xtime_lock);
/* This is revolting. We need to set the xtime.tv_usec
/* This is revolting. We need to set the xtime.tv_nsec
* correctly. However, the value in this location is
* is value at the last tick.
* Discover what correction gettimeofday
......@@ -131,7 +116,8 @@ void do_settimeofday(struct timeval *tv)
tv->tv_sec--;
}
xtime = *tv;
xtime.tv_sec = tv->tv_sec;
xtime.tv_nsec = tv->tv_usec * 1000;
time_adjust = 0; /* stop active adjtime() */
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
......@@ -139,58 +125,90 @@ void do_settimeofday(struct timeval *tv)
write_unlock_irq(&xtime_lock);
}
static inline __u32 div64_32(__u64 dividend, __u32 divisor)
{
register_pair rp;
rp.pair = dividend;
asm ("dr %0,%1" : "+d" (rp) : "d" (divisor));
return rp.subreg.odd;
}
/*
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
#ifdef CONFIG_SMP
extern __u16 boot_cpu_addr;
#endif
static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
{
int cpu = smp_processor_id();
__u64 tmp;
__u32 ticks;
/* Calculate how many ticks have passed. */
asm volatile ("STCK 0(%0)" : : "a" (&tmp) : "memory", "cc");
tmp = tmp - S390_lowcore.jiffy_timer;
if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than one tick ? */
ticks = div64_32(tmp >> 1, CLK_TICKS_PER_JIFFY >> 1);
S390_lowcore.jiffy_timer +=
CLK_TICKS_PER_JIFFY * (__u64) ticks;
} else {
ticks = 1;
S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
}
irq_enter(cpu, 0);
/* set clock comparator for next tick */
tmp = S390_lowcore.jiffy_timer + CLK_TICKS_PER_JIFFY + CPU_DEVIATION;
asm volatile ("SCKC %0" : : "m" (tmp));
/*
* set clock comparator for next tick
*/
S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
irq_enter();
#ifdef CONFIG_SMP
if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr)
write_lock(&xtime_lock);
update_process_times(user_mode(regs));
if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) {
do_timer(regs);
write_unlock(&xtime_lock);
/*
* Do not rely on the boot cpu to do the calls to do_timer.
* Spread it over all cpus instead.
*/
write_lock(&xtime_lock);
if (S390_lowcore.jiffy_timer > xtime_cc) {
__u32 xticks;
tmp = S390_lowcore.jiffy_timer - xtime_cc;
if (tmp >= 2*CLK_TICKS_PER_JIFFY) {
xticks = div64_32(tmp >> 1, CLK_TICKS_PER_JIFFY >> 1);
xtime_cc += (__u64) xticks * CLK_TICKS_PER_JIFFY;
} else {
xticks = 1;
xtime_cc += CLK_TICKS_PER_JIFFY;
}
while (xticks--)
do_timer(regs);
}
write_unlock(&xtime_lock);
while (ticks--)
update_process_times(user_mode(regs));
#else
do_timer(regs);
while (ticks--)
do_timer(regs);
#endif
irq_exit(cpu, 0);
irq_exit();
}
/*
* Start the clock comparator on the current CPU
* Start the clock comparator on the current CPU.
*/
void init_cpu_timer(void)
{
unsigned long cr0;
__u64 timer;
/* allow clock comparator timer interrupt */
asm volatile ("STCTL 0,0,%0" : "=m" (cr0) : : "memory");
cr0 |= 0x800;
asm volatile ("LCTL 0,0,%0" : : "m" (cr0) : "memory");
S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
timer = init_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY;
S390_lowcore.jiffy_timer = timer;
timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION;
asm volatile ("SCKC %0" : : "m" (timer));
}
/*
......@@ -199,7 +217,7 @@ void init_cpu_timer(void)
*/
void __init time_init(void)
{
__u64 set_time_cc;
__u64 set_time_cc;
int cc;
/* kick the TOD clock */
......@@ -222,8 +240,9 @@ void __init time_init(void)
}
/* set xtime */
set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
(0x3c26700LL*1000000*4096);
xtime_cc = init_timer_cc;
set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
(0x3c26700LL*1000000*4096);
tod_to_timeval(set_time_cc, &xtime);
/* request the 0x1004 external interrupt */
......
......@@ -116,22 +116,22 @@ void show_trace(unsigned long * stack)
stack = (unsigned long*)&stack;
printk("Call Trace: ");
low_addr = ((unsigned long) stack) & PSW_ADDR_MASK;
low_addr = ((unsigned long) stack) & PSW_ADDR_INSN;
high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE;
/* Skip the first frame (biased stack) */
backchain = *((unsigned long *) low_addr) & PSW_ADDR_MASK;
backchain = *((unsigned long *) low_addr) & PSW_ADDR_INSN;
/* Print up to 8 lines */
for (i = 0; i < 8; i++) {
if (backchain < low_addr || backchain >= high_addr)
break;
ret_addr = *((unsigned long *) (backchain+56)) & PSW_ADDR_MASK;
ret_addr = *((unsigned long *) (backchain+56)) & PSW_ADDR_INSN;
if (!kernel_text_address(ret_addr))
break;
if (i && ((i % 6) == 0))
printk("\n ");
printk("[<%08lx>] ", ret_addr);
low_addr = backchain;
backchain = *((unsigned long *) backchain) & PSW_ADDR_MASK;
backchain = *((unsigned long *) backchain) & PSW_ADDR_INSN;
}
printk("\n");
}
......@@ -170,13 +170,21 @@ void show_stack(unsigned long *sp)
show_trace(sp);
}
/*
* The architecture-independent dump_stack generator
*/
void dump_stack(void)
{
show_stack(0);
}
void show_registers(struct pt_regs *regs)
{
mm_segment_t old_fs;
char *mode;
int i;
mode = (regs->psw.mask & PSW_PROBLEM_STATE) ? "User" : "Krnl";
mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl";
printk("%s PSW : %08lx %08lx\n",
mode, (unsigned long) regs->psw.mask,
(unsigned long) regs->psw.addr);
......@@ -202,7 +210,7 @@ void show_registers(struct pt_regs *regs)
* time of the fault.
*/
old_fs = get_fs();
if (regs->psw.mask & PSW_PROBLEM_STATE)
if (regs->psw.mask & PSW_MASK_PSTATE)
set_fs(USER_DS);
else
set_fs(KERNEL_DS);
......@@ -279,10 +287,10 @@ static void inline do_trap(long interruption_code, int signr, char *str,
* We got all needed information from the lowcore and can
* now safely switch on interrupts.
*/
if (regs->psw.mask & PSW_PROBLEM_STATE)
if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable();
if (regs->psw.mask & PSW_PROBLEM_STATE) {
if (regs->psw.mask & PSW_MASK_PSTATE) {
struct task_struct *tsk = current;
tsk->thread.trap_no = interruption_code & 0xffff;
......@@ -314,12 +322,12 @@ static void inline do_trap(long interruption_code, int signr, char *str,
static inline void *get_check_address(struct pt_regs *regs)
{
return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc);
return (void *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN);
}
int do_debugger_trap(struct pt_regs *regs,int signal)
{
if(regs->psw.mask&PSW_PROBLEM_STATE)
if(regs->psw.mask&PSW_MASK_PSTATE)
{
if(current->ptrace & PT_PTRACED)
force_sig(signal,current);
......@@ -415,10 +423,10 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
* We got all needed information from the lowcore and can
* now safely switch on interrupts.
*/
if (regs->psw.mask & PSW_PROBLEM_STATE)
if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable();
if (regs->psw.mask & PSW_PROBLEM_STATE)
if (regs->psw.mask & PSW_MASK_PSTATE)
get_user(*((__u16 *) opcode), location);
else
*((__u16 *)opcode)=*((__u16 *)location);
......@@ -428,7 +436,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
signal = SIGILL;
}
#ifdef CONFIG_MATHEMU
else if (regs->psw.mask & PSW_PROBLEM_STATE)
else if (regs->psw.mask & PSW_MASK_PSTATE)
{
if (opcode[0] == 0xb3) {
get_user(*((__u16 *) (opcode+2)), location+1);
......@@ -476,10 +484,10 @@ specification_exception(struct pt_regs * regs, long interruption_code)
* We got all needed information from the lowcore and can
* now safely switch on interrupts.
*/
if (regs->psw.mask & PSW_PROBLEM_STATE)
if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable();
if (regs->psw.mask & PSW_PROBLEM_STATE) {
if (regs->psw.mask & PSW_MASK_PSTATE) {
get_user(*((__u16 *) opcode), location);
switch (opcode[0]) {
case 0x28: /* LDR Rx,Ry */
......@@ -539,7 +547,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
* We got all needed information from the lowcore and can
* now safely switch on interrupts.
*/
if (regs->psw.mask & PSW_PROBLEM_STATE)
if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable();
if (MACHINE_HAS_IEEE)
......@@ -547,7 +555,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
: "=m" (current->thread.fp_regs.fpc));
#ifdef CONFIG_MATHEMU
else if (regs->psw.mask & PSW_PROBLEM_STATE) {
else if (regs->psw.mask & PSW_MASK_PSTATE) {
__u8 opcode[6];
get_user(*((__u16 *) opcode), location);
switch (opcode[0]) {
......@@ -671,21 +679,19 @@ void __init trap_init(void)
void handle_per_exception(struct pt_regs *regs)
{
if(regs->psw.mask&PSW_PROBLEM_STATE)
{
if (regs->psw.mask & PSW_MASK_PSTATE) {
per_struct *per_info=&current->thread.per_info;
per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid;
per_info->lowcore.words.address=S390_lowcore.per_address;
per_info->lowcore.words.access_id=S390_lowcore.per_access_id;
}
if(do_debugger_trap(regs,SIGTRAP))
{
if (do_debugger_trap(regs,SIGTRAP)) {
/* I've seen this possibly a task structure being reused ? */
printk("Spurious per exception detected\n");
printk("switching off per tracing for this task.\n");
show_regs(regs);
/* Hopefully switching off per tracing will help us survive */
regs->psw.mask &= ~PSW_PER_MASK;
regs->psw.mask &= ~PSW_MASK_PER;
}
}
......@@ -6,8 +6,7 @@ L_TARGET = lib.a
EXTRA_AFLAGS := -traditional
obj-y = checksum.o delay.o memset.o misaligned.o strcmp.o strncpy.o uaccess.o
export-objs += misaligned.o
obj-y = delay.o memset.o strcmp.o strncpy.o uaccess.o
include $(TOPDIR)/Rules.make
/*
* arch/s390/lib/checksum.c
* S390 fast network checksum routines
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Ulrich Hild (first version),
* Martin Schwidefsky (schwidefsky@de.ibm.com),
* Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
*
* This file contains network checksum routines
*/
#include <linux/string.h>
#include <linux/types.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <asm/checksum.h>
/*
* computes a partial checksum, e.g. for TCP/UDP fragments
*/
unsigned int
csum_partial (const unsigned char *buff, int len, unsigned int sum)
{
register_pair rp;
/*
* Experiments with ethernet and slip connections show that buff
* is aligned on either a 2-byte or 4-byte boundary.
*/
rp.subreg.even = (unsigned long) buff;
rp.subreg.odd = (unsigned long) len;
__asm__ __volatile__ (
"0: cksm %0,%1\n" /* do checksum on longs */
" jo 0b\n"
: "+&d" (sum), "+&a" (rp) : : "cc" );
return sum;
}
/*
* Fold a partial checksum without adding pseudo headers
*/
unsigned short csum_fold(unsigned int sum)
{
register_pair rp;
__asm__ __volatile__ (
" slr %N1,%N1\n" /* %0 = H L */
" lr %1,%0\n" /* %0 = H L, %1 = H L 0 0 */
" srdl %1,16\n" /* %0 = H L, %1 = 0 H L 0 */
" alr %1,%N1\n" /* %0 = H L, %1 = L H L 0 */
" alr %0,%1\n" /* %0 = H+L+C L+H */
" srl %0,16\n" /* %0 = H+L+C */
: "+&d" (sum), "=d" (rp) : : "cc" );
return ((unsigned short) ~sum);
}
/*
* arch/s390/lib/misaligned.c
* S390 misalignment panic stubs
*
* S390 version
* Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com).
*
* xchg wants to panic if the pointer is not aligned. To avoid multiplying
* the panic message over and over again, the panic is done in the helper
* functions __misaligned_u32 and __misaligned_u16.
*/
#include <linux/module.h>
#include <linux/kernel.h>
void __misaligned_u16(void)
{
panic("misaligned (__u16 *) in __xchg\n");
}
void __misaligned_u32(void)
{
panic("misaligned (__u32 *) in __xchg\n");
}
EXPORT_SYMBOL(__misaligned_u16);
EXPORT_SYMBOL(__misaligned_u32);
......@@ -48,7 +48,7 @@ search_exception_table(unsigned long addr)
addr &= 0x7fffffff; /* remove amode bit from address */
/* There is only the kernel to search. */
ret = search_one_table(__start___ex_table, __stop___ex_table-1, addr);
if (ret) ret = FIX_PSW(ret);
if (ret) ret = ret | PSW_ADDR_AMODE31;
return ret;
#else
unsigned long flags;
......@@ -63,7 +63,7 @@ search_exception_table(unsigned long addr)
ret = search_one_table(mp->ex_table_start,
mp->ex_table_end - 1, addr);
if (ret) {
ret = FIX_PSW(ret);
ret = ret | PSW_ADDR_AMODE31;
break;
}
}
......
......@@ -46,7 +46,6 @@ extern spinlock_t timerlist_lock;
*/
void bust_spinlocks(int yes)
{
spin_lock_init(&timerlist_lock);
if (yes) {
oops_in_progress = 1;
} else {
......@@ -167,7 +166,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
/* Low-address protection hit in kernel mode means
NULL pointer write access in kernel mode. */
if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
address = 0;
user_address = 0;
goto no_context;
......@@ -234,16 +233,18 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
* the fault.
*/
switch (handle_mm_fault(mm, vma, address, error_code == 4)) {
case 1:
case VM_FAULT_MINOR:
tsk->min_flt++;
break;
case 2:
case VM_FAULT_MAJOR:
tsk->maj_flt++;
break;
case 0:
case VM_FAULT_SIGBUS:
goto do_sigbus;
default:
case VM_FAULT_OOM:
goto out_of_memory;
default:
BUG();
}
up_read(&mm->mmap_sem);
......@@ -257,7 +258,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
up_read(&mm->mmap_sem);
/* User mode accesses just cause a SIGSEGV */
if (regs->psw.mask & PSW_PROBLEM_STATE) {
if (regs->psw.mask & PSW_MASK_PSTATE) {
tsk->thread.prot_addr = address;
tsk->thread.trap_no = error_code;
force_sigsegv(regs, error_code, si_code, address);
......@@ -297,7 +298,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
goto survive;
}
printk("VM: killing process %s\n", tsk->comm);
if (regs->psw.mask & PSW_PROBLEM_STATE)
if (regs->psw.mask & PSW_MASK_PSTATE)
do_exit(SIGKILL);
goto no_context;
......@@ -313,7 +314,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code)
force_sig(SIGBUS, tsk);
/* Kernel mode? Handle exceptions or die */
if (!(regs->psw.mask & PSW_PROBLEM_STATE))
if (!(regs->psw.mask & PSW_MASK_PSTATE))
goto no_context;
}
......@@ -392,7 +393,7 @@ do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code)
spin_unlock(&pseudo_wait_spinlock);
} else {
/* Pseudo page faults in kernel mode is a bad idea */
if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
/*
* VM presents pseudo page faults if the interrupted
* state was not disabled for interrupts. So we can
......@@ -527,7 +528,7 @@ pfault_interrupt(struct pt_regs *regs, __u16 error_code)
* We got all needed information from the lowcore and can
* now safely switch on interrupts.
*/
if (regs->psw.mask & PSW_PROBLEM_STATE)
if (regs->psw.mask & PSW_MASK_PSTATE)
local_irq_enable();
if (subcode & 0x0080) {
......
/* ld script to make s390 Linux kernel
* Written by Martin Schwidefsky (schwidefsky@de.ibm.com)
*/
OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390")
OUTPUT_ARCH(s390)
ENTRY(_start)
jiffies = jiffies_64 + 4;
SECTIONS
{
. = 0x00000000;
_text = .; /* Text and read-only data */
.text : {
*(.text)
*(.fixup)
*(.gnu.warning)
} = 0x0700
_etext = .; /* End of text section */
.rodata : { *(.rodata) }
.kstrtab : { *(.kstrtab) }
. = ALIGN(16); /* Exception table */
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
__start___ksymtab = .; /* Kernel symbol table */
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
. = ALIGN(1048576); /* VM shared segments are 1MB aligned */
_eshared = .; /* End of shareable data */
.data : { /* Data */
*(.data)
CONSTRUCTORS
}
_edata = .; /* End of data section */
. = ALIGN(8192); /* init_task */
.data.init_task : { *(.data.init_task) }
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
.text.init : { *(.text.init) }
.data.init : { *(.data.init) }
. = ALIGN(256);
__setup_start = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
__initcall_end = .;
. = ALIGN(256);
__per_cpu_start = .;
.date.percpu : { *(.data.percpu) }
__per_cpu_end = .;
. = ALIGN(4096);
__init_end = .;
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
. = ALIGN(4096);
.data.page_aligned : { *(.data.idt) }
__bss_start = .; /* BSS */
.bss : {
*(.bss)
}
_end = . ;
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
}
/* ld script to make s390 Linux kernel
* Written by Martin Schwidefsky (schwidefsky@de.ibm.com)
*/
OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390")
OUTPUT_ARCH(s390)
ENTRY(_start)
jiffies = jiffies_64 + 4;
SECTIONS
{
. = 0x00000000;
_text = .; /* Text and read-only data */
.text : {
*(.text)
*(.fixup)
*(.gnu.warning)
} = 0x0700
_etext = .; /* End of text section */
.rodata : { *(.rodata) *(.rodata.*) }
.kstrtab : { *(.kstrtab) }
. = ALIGN(16); /* Exception table */
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
__start___ksymtab = .; /* Kernel symbol table */
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
.data : { /* Data */
*(.data)
CONSTRUCTORS
}
_edata = .; /* End of data section */
. = ALIGN(8192); /* init_task */
.data.init_task : { *(.data.init_task) }
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
.text.init : { *(.text.init) }
.data.init : { *(.data.init) }
. = ALIGN(256);
__setup_start = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
__initcall_end = .;
. = ALIGN(256);
__per_cpu_start = .;
.date.percpu : { *(.data.percpu) }
__per_cpu_end = .;
. = ALIGN(4096);
__init_end = .;
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
. = ALIGN(4096);
.data.page_aligned : { *(.data.idt) }
__bss_start = .; /* BSS */
.bss : {
*(.bss)
}
_end = . ;
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
}
#include <linux/config.h>
/* ld script to make s390 Linux kernel
* Written by Martin Schwidefsky (schwidefsky@de.ibm.com)
*/
OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390")
OUTPUT_ARCH(s390)
ENTRY(_start)
jiffies = jiffies_64 + 4;
SECTIONS
{
. = 0x00000000;
_text = .; /* Text and read-only data */
.text : {
*(.text)
*(.fixup)
*(.gnu.warning)
} = 0x0700
_etext = .; /* End of text section */
.rodata : { *(.rodata) *(.rodata.*) }
.kstrtab : { *(.kstrtab) }
. = ALIGN(16); /* Exception table */
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
__start___ksymtab = .; /* Kernel symbol table */
__ksymtab : { *(__ksymtab) }
__stop___ksymtab = .;
#ifdef CONFIG_SHARED_KERNEL
#include "vmlinux-shared.lds"
#else
#include "vmlinux.lds"
. = ALIGN(1048576); /* VM shared segments are 1MB aligned */
_eshared = .; /* End of shareable data */
#endif
.data : { /* Data */
*(.data)
CONSTRUCTORS
}
_edata = .; /* End of data section */
. = ALIGN(8192); /* init_task */
.data.init_task : { *(.data.init_task) }
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
.text.init : { *(.text.init) }
.data.init : { *(.data.init) }
. = ALIGN(256);
__setup_start = .;
.setup.init : { *(.setup.init) }
__setup_end = .;
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
__initcall_end = .;
. = ALIGN(256);
__per_cpu_start = .;
.date.percpu : { *(.data.percpu) }
__per_cpu_end = .;
. = ALIGN(4096);
__init_end = .;
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
. = ALIGN(4096);
.data.page_aligned : { *(.data.idt) }
__bss_start = .; /* BSS */
.bss : {
*(.bss)
}
_end = . ;
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
}
......@@ -159,25 +159,11 @@ CONFIG_IPL_TAPE
Select "vm_reader" if you are running under VM/ESA and want
to IPL the image from the emulated card reader.
CONFIG_FAST_IRQ
Select this option in order to get the interrupts processed faster
on your S/390 or zSeries machine. If selected, after an interrupt
is processed, the channel subsystem will be asked for other pending
interrupts which will also be processed before leaving the interrupt
context. This speeds up the I/O a lot. Say "Y".
CONFIG_MACHCHK_WARNING
Select this option if you want the machine check handler on IBM S/390 or
zSeries to process warning machine checks (e.g. on power failures).
If unsure, say "Y".
CONFIG_CHSC
Select this option if you want the s390 common I/O layer to use information
obtained by channel subsystem calls. This will enable Linux to process link
failures and resource accessibility events. Moreover, if you have procfs
enabled, you'll be able to toggle chpids logically offline and online. Even
if you don't understand what this means, you should say "Y".
CONFIG_S390_SUPPORT
Select this option if you want to enable your system kernel to
handle system-calls from ELF binaries for 31 bit ESA. This option
......
......@@ -26,7 +26,7 @@ HEAD := arch/s390x/kernel/head.o arch/s390x/kernel/init_task.o
core-y += arch/s390x/mm/ arch/s390x/kernel/
drivers-y += drivers/s390/
libs-y += arch/s390/lib/
libs-y += arch/s390x/lib/
all: image listing
......
......@@ -17,31 +17,30 @@ define_bool CONFIG_ARCH_S390X y
source init/Config.in
mainmenu_option next_comment
comment 'Base setup'
comment 'Processor type and features'
bool 'Symmetric multi-processing support' CONFIG_SMP
bool 'Kernel support for 31 bit emulation' CONFIG_S390_SUPPORT
if [ "$CONFIG_S390_SUPPORT" = "y" ]; then
tristate 'Kernel support for 31 bit ELF binaries' CONFIG_BINFMT_ELF32
fi
endmenu
mainmenu_option next_comment
comment 'Base setup'
bool 'Fast IRQ handling' CONFIG_FAST_IRQ
comment 'I/O subsystem configuration'
bool 'Process warning machine checks' CONFIG_MACHCHK_WARNING
bool 'Use chscs for Common I/O' CONFIG_CHSC
tristate 'QDIO support' CONFIG_QDIO
if [ "$CONFIG_QDIO" != "n" ]; then
bool ' Performance statistics in /proc' CONFIG_QDIO_PERF_STATS
fi
if [ "$CONFIG_QDIO" != "n" ]; then
bool ' Performance statistics in /proc' CONFIG_QDIO_PERF_STATS
fi
comment 'Misc'
bool 'Preemptible Kernel' CONFIG_PREEMPT
bool 'Builtin IPL record support' CONFIG_IPL
if [ "$CONFIG_IPL" = "y" ]; then
choice 'IPL method generated into head.S' \
"tape CONFIG_IPL_TAPE \
vm_reader CONFIG_IPL_VM" tape
fi
define_bool CONFIG_KCORE_ELF y
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
......@@ -71,7 +70,6 @@ source fs/Config.in
mainmenu_option next_comment
comment 'Kernel hacking'
#bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC
#if [ "$CONFIG_CTC" = "y" ]; then
# bool 'Remote GDB kernel debugging' CONFIG_REMOTE_DEBUG
#fi
......
......@@ -30,6 +30,10 @@ CONFIG_MODULES=y
# CONFIG_MODVERSIONS is not set
CONFIG_KMOD=y
#
# Base setup
#
#
# Processor type and features
#
......@@ -38,13 +42,16 @@ CONFIG_S390_SUPPORT=y
CONFIG_BINFMT_ELF32=y
#
# Base setup
# I/O subsystem configuration
#
CONFIG_FAST_IRQ=y
CONFIG_MACHCHK_WARNING=y
CONFIG_CHSC=y
CONFIG_QDIO=m
CONFIG_QDIO=y
# CONFIG_QDIO_PERF_STATS is not set
#
# Misc
#
# CONFIG_PREEMPT is not set
CONFIG_IPL=y
# CONFIG_IPL_TAPE is not set
CONFIG_IPL_VM=y
......@@ -85,9 +92,6 @@ CONFIG_SCSI_LOGGING=y
#
# CONFIG_SCSI_7000FASST is not set
# CONFIG_SCSI_ACARD is not set
# CONFIG_SCSI_AHA152X is not set
# CONFIG_SCSI_AHA1542 is not set
# CONFIG_SCSI_AHA1740 is not set
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_DPT_I2O is not set
......@@ -115,7 +119,6 @@ CONFIG_SCSI_LOGGING=y
# CONFIG_SCSI_PCI2220I is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_SIM710 is not set
# CONFIG_SCSI_SYM53C416 is not set
# CONFIG_SCSI_T128 is not set
# CONFIG_SCSI_U14_34F is not set
......@@ -153,7 +156,7 @@ CONFIG_MD_RAID0=m
CONFIG_MD_RAID1=m
CONFIG_MD_RAID5=m
# CONFIG_MD_MULTIPATH is not set
CONFIG_BLK_DEV_LVM=m
# CONFIG_BLK_DEV_LVM is not set
#
# Character device drivers
......@@ -225,26 +228,23 @@ CONFIG_IP_MULTICAST=y
# CONFIG_ARPD is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
CONFIG_IPV6=m
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_IPV6 is not set
#
#
# SCTP Configuration (EXPERIMENTAL)
#
CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_LLC is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
#
# Appletalk devices
#
# CONFIG_DEV_APPLETALK is not set
# CONFIG_DECNET is not set
# CONFIG_BRIDGE is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
# CONFIG_LLC is not set
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
......@@ -299,7 +299,7 @@ CONFIG_RAMFS=y
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
CONFIG_DEVFS_FS=y
CONFIG_DEVFS_MOUNT=y
# CONFIG_DEVFS_MOUNT is not set
# CONFIG_DEVFS_DEBUG is not set
# CONFIG_DEVPTS_FS is not set
# CONFIG_QNX4FS_FS is not set
......@@ -311,6 +311,9 @@ CONFIG_EXT2_FS=y
# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
# CONFIG_UFS_FS_WRITE is not set
# CONFIG_XFS_FS is not set
# CONFIG_XFS_RT is not set
# CONFIG_XFS_QUOTA is not set
#
# Network File Systems
......@@ -320,12 +323,12 @@ CONFIG_EXT2_FS=y
CONFIG_NFS_FS=y
# CONFIG_NFS_V3 is not set
# CONFIG_ROOT_NFS is not set
# CONFIG_NFSD is not set
CONFIG_NFSD=y
# CONFIG_NFSD_V3 is not set
# CONFIG_NFSD_TCP is not set
CONFIG_SUNRPC=y
CONFIG_LOCKD=y
# CONFIG_EXPORTFS is not set
CONFIG_EXPORTFS=y
# CONFIG_SMB_FS is not set
# CONFIG_NCP_FS is not set
# CONFIG_NCPFS_PACKET_SIGNING is not set
......@@ -362,6 +365,11 @@ CONFIG_IBM_PARTITION=y
#
CONFIG_MAGIC_SYSRQ=y
#
# Security options
#
CONFIG_SECURITY_CAPABILITIES=y
#
# Library routines
#
......
......@@ -5,12 +5,12 @@
EXTRA_TARGETS := head.o init_task.o
EXTRA_AFLAGS := -traditional
export-objs := debug.o ebcdic.o irq.o s390_ext.o smp.o s390_ksyms.o \
export-objs := debug.o ebcdic.o s390_ext.o smp.o s390_ksyms.o \
exec32.o
obj-y := entry.o bitmap.o traps.o time.o process.o irq.o \
obj-y := entry.o bitmap.o traps.o time.o process.o \
setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
semaphore.o s390fpu.o reipl.o s390_ext.o debug.o
semaphore.o reipl.o s390_ext.o debug.o
obj-$(CONFIG_MODULES) += s390_ksyms.o
obj-$(CONFIG_SMP) += smp.o
......
......@@ -21,6 +21,7 @@
#include <asm/semaphore.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/debug.h>
......@@ -146,7 +147,7 @@ static debug_info_t *debug_area_first = NULL;
static debug_info_t *debug_area_last = NULL;
DECLARE_MUTEX(debug_lock);
static int initialized = 0;
static int initialized;
static struct file_operations debug_file_ops = {
read: debug_output,
......@@ -591,7 +592,7 @@ debug_info_t *debug_register
MOD_INC_USE_COUNT;
if (!initialized)
debug_init();
BUG();
down(&debug_lock);
/* create new debug_info */
......@@ -828,18 +829,16 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id,
* - is called exactly once to initialize the debug feature
*/
int debug_init(void)
static int __init debug_init(void)
{
int rc = 0;
down(&debug_lock);
if (!initialized) {
#ifdef CONFIG_PROC_FS
debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
#endif /* CONFIG_PROC_FS */
printk(KERN_INFO "debug: Initialization complete\n");
initialized = 1;
}
printk(KERN_INFO "debug: Initialization complete\n");
initialized = 1;
up(&debug_lock);
return rc;
......@@ -1173,27 +1172,9 @@ int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
}
/*
* init_module:
*/
#ifdef MODULE
int init_module(void)
{
int rc = 0;
#ifdef DEBUG
printk("debug_module_init: \n");
#endif
rc = debug_init();
if (rc)
printk(KERN_INFO "debug: an error occurred with debug_init\n");
return rc;
}
/*
* cleanup_module:
* clean up module
*/
void cleanup_module(void)
void __exit debug_exit(void)
{
#ifdef DEBUG
printk("debug_cleanup_module: \n");
......@@ -1204,7 +1185,12 @@ void cleanup_module(void)
return;
}
#endif /* MODULE */
/*
* module definitions
*/
core_initcall(debug_init);
module_exit(debug_exit);
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(debug_register);
EXPORT_SYMBOL(debug_unregister);
......
......@@ -15,7 +15,6 @@
#include <asm/cache.h>
#include <asm/lowcore.h>
#include <asm/errno.h>
#include <asm/smp.h>
#include <asm/ptrace.h>
#include <asm/thread_info.h>
......@@ -49,7 +48,7 @@ SP_ORIG_R2 = STACK_FRAME_OVERHEAD + PT_ORIGGPR2
SP_TRAP = (SP_ORIG_R2+GPR_SIZE)
SP_SIZE = (SP_TRAP+4)
_TIF_WORK_MASK = (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED)
_TIF_WORK_MASK = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
/*
* Register usage in interrupt handlers:
......@@ -185,32 +184,42 @@ sysc_leave:
RESTORE_ALL 1
#
# One of the work bits _TIF_NOTIFY_RESUME, _TIF_SIGPENDING or
# _TIF_NEED_RESCHED is on. Find out which one.
# recheck if there is more work to do
#
sysc_work_loop:
stnsm 48(%r15),0xfc # disable I/O and ext. interrupts
GET_THREAD_INFO # load pointer to task_struct to R9
tm __TI_flags+7(%r9),_TIF_WORK_MASK
jz sysc_leave # there is no work to do
#
# One of the work bits is on. Find out which one.
# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED
#
sysc_work:
tm SP_PSW+1(%r15),0x01 # returning to user ?
jno sysc_leave # no-> skip resched & signal
tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
jo sysc_reschedule
# add a test for TIF_NOTIFY_RESUME here when it is used.
# _TIF_SIGPENDING is the only flag left
tm __TI_flags+7(%r9),_TIF_SIGPENDING
jo sysc_sigpending
j sysc_leave
#
# call do_signal before return
#
sysc_signal_return:
la %r2,SP_PTREGS(%r15) # load pt_regs
sgr %r3,%r3 # clear *oldset
larl %r14,sysc_return
jg do_signal # return point is sysc_return
# _TIF_NEED_RESCHED is set, call schedule
#
sysc_reschedule:
stosm 48(%r15),0x03 # reenable interrupts
larl %r14,sysc_work_loop
jg schedule # return point is sysc_return
#
# call schedule with sysc_return as return-address
# _TIF_SIGPENDING is set, call do_signal
#
sysc_reschedule:
larl %r14,sysc_return
jg schedule # return point is sysc_return
sysc_sigpending:
stosm 48(%r15),0x03 # reenable interrupts
la %r2,SP_PTREGS(%r15) # load pt_regs
sgr %r3,%r3 # clear *oldset
brasl %r14,do_signal # call do_signal
stnsm 48(%r15),0xfc # disable I/O and ext. interrupts
j sysc_leave # out of here, do NOT recheck
#
# call syscall_trace before and after system call
......@@ -242,8 +251,7 @@ sysc_tracego:
.globl ret_from_fork
ret_from_fork:
GET_THREAD_INFO # load pointer to task_struct to R9
xc SP_R2(8,%r15),SP_R2(%r15) # child returns 0
#ifdef CONFIG_SMP
#if CONFIG_SMP || CONFIG_PREEMPT
larl %r14,sysc_return
jg schedule_tail # return to sysc_return
#else
......@@ -551,8 +559,8 @@ sys_call_table:
.long SYSCALL(sys_rt_sigtimedwait,sys32_rt_sigtimedwait_wrapper)
.long SYSCALL(sys_rt_sigqueueinfo,sys32_rt_sigqueueinfo_wrapper)
.long SYSCALL(sys_rt_sigsuspend_glue,sys32_rt_sigsuspend_glue)
.long SYSCALL(sys_pread,sys32_pread_wrapper) /* 180 */
.long SYSCALL(sys_pwrite,sys32_pwrite_wrapper)
.long SYSCALL(sys_pread64,sys32_pread64_wrapper) /* 180 */
.long SYSCALL(sys_pwrite64,sys32_pwrite64_wrapper)
.long SYSCALL(sys_ni_syscall,sys32_chown16_wrapper) /* old chown16 syscall */
.long SYSCALL(sys_getcwd,sys32_getcwd_wrapper)
.long SYSCALL(sys_capget,sys32_capget_wrapper)
......@@ -606,13 +614,21 @@ sys_call_table:
.long SYSCALL(sys_flistxattr,sys32_flistxattr_wrapper)
.long SYSCALL(sys_removexattr,sys32_removexattr_wrapper)
.long SYSCALL(sys_lremovexattr,sys32_lremovexattr_wrapper)
.long SYSCALL(sys_fremovexattr,sys32_fremovexattr_wrapper)
.long SYSCALL(sys_fremovexattr,sys32_fremovexattr_wrapper) /* 235 */
.long SYSCALL(sys_gettid,sys_gettid)
.long SYSCALL(sys_tkill,sys_tkill)
.long SYSCALL(sys_futex,sys32_futex_wrapper)
.long SYSCALL(sys_sched_setaffinity,sys32_sched_setaffinity_wrapper)
.long SYSCALL(sys_sched_getaffinity,sys32_sched_getaffinity_wrapper)
.rept 255-240
.long SYSCALL(sys_sched_getaffinity,sys32_sched_getaffinity_wrapper) /* 240 */
.long SYSCALL(sys_security,sys_ni_syscall)
.long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* reserved for TUX */
.long SYSCALL(sys_io_setup,sys_ni_syscall)
.long SYSCALL(sys_io_destroy,sys_ni_syscall)
.long SYSCALL(sys_io_getevents,sys_ni_syscall) /* 245 */
.long SYSCALL(sys_io_submit,sys_ni_syscall)
.long SYSCALL(sys_io_cancel,sys_ni_syscall)
.long SYSCALL(sys_exit_group,sys32_exit_group_wrapper)
.rept 255-248
.long SYSCALL(sys_ni_syscall,sys_ni_syscall)
.endr
......@@ -638,13 +654,15 @@ pgm_check_handler:
tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
jnz pgm_per # got per exception -> special case
SAVE_ALL __LC_PGM_OLD_PSW,1
llgh %r8,__LC_PGM_INT_CODE
lghi %r8,0x7f
lgf %r3,__LC_PGM_ILC # load program interruption code
ngr %r8,%r3
sll %r8,3
GET_THREAD_INFO
stosm 48(%r15),0x03 # reenable interrupts
larl %r1,pgm_check_table
lg %r1,0(%r8,%r1) # load address of handler routine
la %r2,SP_PTREGS(%r15) # address of register-save area
lgf %r3,__LC_PGM_ILC # load program interruption code
larl %r14,sysc_return
br %r1 # branch to interrupt-handler
......@@ -668,6 +686,7 @@ pgm_per_std:
GET_THREAD_INFO
lghi %r4,0x7f
lgf %r3,__LC_PGM_ILC # load program interruption code
stosm 48(%r15),0x03 # reenable interrupts
nr %r4,%r3 # clear per-event-bit and ilc
je pgm_per_only # only per of per+check ?
sll %r4,3
......@@ -751,57 +770,79 @@ io_int_handler:
brasl %r14,do_IRQ # call standard irq handler
io_return:
#
# check, if bottom-half has to be done
#
lgf %r1,__TI_cpu(%r9)
larl %r2,irq_stat
sll %r1,L1_CACHE_SHIFT
la %r1,0(%r1,%r2)
icm %r0,15,0(%r1) # test irq_stat[#cpu].__softirq_pending
jnz io_handle_bottom_half
io_return_bh:
tm SP_PSW+1(%r15),0x01 # returning to user ?
#ifdef CONFIG_PREEMPT
jno io_preempt # no -> check for preemptive scheduling
#else
jno io_leave # no-> skip resched & signal
#endif
tm __TI_flags+7(%r9),_TIF_WORK_MASK
jnz io_work # there is work to do (signals etc.)
io_leave:
stnsm 48(%r15),0xfc # disable I/O and ext. interrupts
RESTORE_ALL 0
#ifdef CONFIG_PREEMPT
io_preempt:
icm %r0,15,__TI_precount(%r9)
jnz io_leave
io_resume_loop:
tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
jno io_leave
larl %r1,.Lc_pactive
mvc __TI_precount(4,%r9),0(%r1)
# hmpf, we are on the async. stack but to call schedule
# we have to move the interrupt frame to the process stack
lg %r1,SP_R15(%r15)
aghi %r1,-SP_SIZE
nill %r1,0xfff8
mvc SP_PTREGS(SP_SIZE-SP_PTREGS,%r1),SP_PTREGS(%r15)
xc 0(8,%r1),0(%r1) # clear back chain
lgr %r15,%r1
stosm 48(%r15),0x03 # reenable interrupts
brasl %r14,schedule # call schedule
stnsm 48(%r15),0xfc # disable I/O and ext. interrupts
GET_THREAD_INFO # load pointer to task_struct to R9
xc __TI_precount(4,%r9),__TI_precount(%r9)
j io_resume_loop
#endif
#
# call do_softirq
# recheck if there is more work to do
#
io_handle_bottom_half:
larl %r14,io_return_bh
jg do_softirq # return point is io_return_bh
io_work_loop:
stnsm 48(%r15),0xfc # disable I/O and ext. interrupts
GET_THREAD_INFO # load pointer to task_struct to R9
tm __TI_flags+7(%r9),_TIF_WORK_MASK
jz io_leave # there is no work to do
#
# One of the work bits _TIF_NOTIFY_RESUME, _TIF_SIGPENDING or
# _TIF_NEED_RESCHED is on. Find out which one.
# One of the work bits is on. Find out which one.
# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED
#
io_work:
tm SP_PSW+1(%r15),0x01 # returning to user ?
jno io_leave # no-> skip resched & signal
stosm 48(%r15),0x03 # reenable interrupts
tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
jo io_reschedule
# add a test for TIF_NOTIFY_RESUME here when it is used.
# _TIF_SIGPENDING is the only flag left
tm __TI_flags+7(%r9),_TIF_SIGPENDING
jo io_sigpending
j io_leave
#
# call do_signal before return
#
io_signal_return:
la %r2,SP_PTREGS(%r15) # load pt_regs
slgr %r3,%r3 # clear *oldset
larl %r14,io_leave
jg do_signal # return point is io_leave
# _TIF_NEED_RESCHED is set, call schedule
#
io_reschedule:
stosm 48(%r15),0x03 # reenable interrupts
larl %r14,io_work_loop
jg schedule # call scheduler
#
# call schedule with io_return as return-address
# _TIF_SIGPENDING is set, call do_signal
#
io_reschedule:
larl %r14,io_return
jg schedule # call scheduler, return to io_return
io_sigpending:
stosm 48(%r15),0x03 # reenable interrupts
la %r2,SP_PTREGS(%r15) # load pt_regs
slgr %r3,%r3 # clear *oldset
brasl %r14,do_signal # call do_signal
stnsm 48(%r15),0xfc # disable I/O and ext. interrupts
j sysc_leave # out of here, do NOT recheck
/*
* External interrupt handler routine
......@@ -875,4 +916,5 @@ restart_go:
*/
.align 4
.Lc_ac: .long 0,0,1
.Lc_pactive: .long PREEMPT_ACTIVE
.Lc256: .quad 256
......@@ -555,6 +555,17 @@ startup:basr %r13,0 # get base
oi 7(%r12),16 # set MVPG flag
0:
#
# find out if the diag 0x44 works in 64 bit mode
#
la %r1,0f-.LPG1(%r13) # set program check address
stg %r1,__LC_PGM_NEW_PSW+8
mvc __LC_DIAG44_OPCODE(8),.Lnop-.LPG1(%r13)
diag 0,0,0x44 # test diag 0x44
oi 7(%r12),32 # set diag44 flag
mvc __LC_DIAG44_OPCODE(8),.Ldiag44-.LPG1(%r13)
0:
lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space,
# virtual and never return ...
.align 16
......@@ -578,6 +589,8 @@ startup:basr %r13,0 # get base
.Lpcmsk:.quad 0x0000000180000000
.L4malign:.quad 0xffffffffffc00000
.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
.Lnop: .long 0x07000700
.Ldiag44:.long 0x83000044
.org PARMAREA-64
.Lduct: .long 0,0,0,0,0,0,0,0
......@@ -645,5 +658,5 @@ _stext: basr %r13,0 # get base
#
.align 8
.Ldw: .quad 0x0002000180000000,0x0000000000000000
.Laregs: .long 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
.Laregs: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
......@@ -15,7 +15,7 @@
static struct fs_struct init_fs = INIT_FS;
static struct files_struct init_files = INIT_FILES;
static struct signal_struct init_signals = INIT_SIGNALS;
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
struct mm_struct init_mm = INIT_MM(init_mm);
/*
......
/*
* arch/s390/kernel/irq.c
*
* S390 version
* Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Ingo Adlung (adlung@de.ibm.com)
*
* Derived from "arch/i386/kernel/irq.c"
* Copyright (C) 1992, 1999 Linus Torvalds, Ingo Molnar
*
* S/390 I/O interrupt processing and I/O request processing is
* implemented in arch/s390/kernel/s390io.c
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/random.h>
#include <linux/smp.h>
#include <linux/threads.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/seq_file.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/bitops.h>
#include <asm/smp.h>
#include <asm/pgtable.h>
#include <asm/delay.h>
#include <asm/lowcore.h>
void s390_init_IRQ ( void );
void s390_free_irq ( unsigned int irq, void *dev_id);
int s390_request_irq( unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id);
#if 0
/*
* The following vectors are part of the Linux architecture, there
* is no hardware IRQ pin equivalent for them, they are triggered
* through the ICC by us (IPIs), via smp_message_pass():
*/
BUILD_SMP_INTERRUPT(reschedule_interrupt)
BUILD_SMP_INTERRUPT(invalidate_interrupt)
BUILD_SMP_INTERRUPT(stop_cpu_interrupt)
BUILD_SMP_INTERRUPT(mtrr_interrupt)
BUILD_SMP_INTERRUPT(spurious_interrupt)
#endif
int show_interrupts(struct seq_file *p, void *v)
{
int i, j;
seq_puts(p, " ");
for (j=0; j<smp_num_cpus; j++)
seq_printf(p, "CPU%d ",j);
seq_putc(p, '\n');
for (i = 0 ; i < NR_IRQS ; i++)
{
if (ioinfo[i] == INVALID_STORAGE_AREA)
continue;
seq_printf(p, "%3d: ",i);
seq_printf(p, " %s", ioinfo[i]->irq_desc.name);
seq_putc(p, '\n');
} /* endfor */
return 0;
}
/*
* Global interrupt locks for SMP. Allow interrupts to come in on any
* CPU, yet make cli/sti act globally to protect critical regions..
*/
#ifdef CONFIG_SMP
atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID);
atomic_t global_irq_lock = ATOMIC_INIT(0);
atomic_t global_irq_count = ATOMIC_INIT(0);
atomic_t global_bh_count;
/*
* "global_cli()" is a special case, in that it can hold the
* interrupts disabled for a longish time, and also because
* we may be doing TLB invalidates when holding the global
* IRQ lock for historical reasons. Thus we may need to check
* SMP invalidate events specially by hand here (but not in
* any normal spinlocks)
*
* Thankfully we don't need this as we can deliver flush tlbs with
* interrupts disabled DJB :-)
*/
#define check_smp_invalidate(cpu)
extern void show_stack(unsigned long* esp);
static void show(char * str)
{
int cpu = smp_processor_id();
printk("\n%s, CPU %d:\n", str, cpu);
printk("irq: %d [%d]\n",
atomic_read(&global_irq_count),local_irq_count(smp_processor_id()));
printk("bh: %d [%d]\n",
atomic_read(&global_bh_count),local_bh_count(smp_processor_id()));
show_stack(NULL);
}
#define MAXCOUNT 100000000
static inline void wait_on_bh(void)
{
int count = MAXCOUNT;
do {
if (!--count) {
show("wait_on_bh");
count = ~0;
}
/* nothing .. wait for the other bh's to go away */
} while (atomic_read(&global_bh_count) != 0);
}
static inline void wait_on_irq(int cpu)
{
int count = MAXCOUNT;
for (;;) {
/*
* Wait until all interrupts are gone. Wait
* for bottom half handlers unless we're
* already executing in one..
*/
if (!atomic_read(&global_irq_count)) {
if (local_bh_count(cpu)||
!atomic_read(&global_bh_count))
break;
}
/* Duh, we have to loop. Release the lock to avoid deadlocks */
atomic_set(&global_irq_lock, 0);
for (;;) {
if (!--count) {
show("wait_on_irq");
count = ~0;
}
local_irq_enable();
SYNC_OTHER_CORES(cpu);
local_irq_disable();
check_smp_invalidate(cpu);
if (atomic_read(&global_irq_count))
continue;
if (atomic_read(&global_irq_lock))
continue;
if (!local_bh_count(cpu)
&& atomic_read(&global_bh_count))
continue;
if (!atomic_compare_and_swap(0, 1, &global_irq_lock))
break;
}
}
}
/*
* This is called when we want to synchronize with
* bottom half handlers. We need to wait until
* no other CPU is executing any bottom half handler.
*
* Don't wait if we're already running in an interrupt
* context or are inside a bh handler.
*/
void synchronize_bh(void)
{
if (atomic_read(&global_bh_count) && !in_interrupt())
wait_on_bh();
}
/*
* This is called when we want to synchronize with
* interrupts. We may for example tell a device to
* stop sending interrupts: but to make sure there
* are no interrupts that are executing on another
* CPU we need to call this function.
*/
void synchronize_irq(void)
{
if (atomic_read(&global_irq_count)) {
/* Stupid approach */
cli();
sti();
}
}
static inline void get_irqlock(int cpu)
{
if (atomic_compare_and_swap(0,1,&global_irq_lock) != 0) {
/* do we already hold the lock? */
if ( cpu == atomic_read(&global_irq_holder))
return;
/* Uhhuh.. Somebody else got it. Wait.. */
do {
check_smp_invalidate(cpu);
} while (atomic_compare_and_swap(0,1,&global_irq_lock) != 0);
}
/*
* We also to make sure that nobody else is running
* in an interrupt context.
*/
wait_on_irq(cpu);
/*
* Ok, finally..
*/
atomic_set(&global_irq_holder,cpu);
}
#define EFLAGS_I_SHIFT 57
/*
* A global "cli()" while in an interrupt context
* turns into just a local cli(). Interrupts
* should use spinlocks for the (very unlikely)
* case that they ever want to protect against
* each other.
*
* If we already have local interrupts disabled,
* this will not turn a local disable into a
* global one (problems with spinlocks: this makes
* save_flags+cli+sti usable inside a spinlock).
*/
void __global_cli(void)
{
unsigned long flags;
local_save_flags(flags);
if (flags & (1UL << EFLAGS_I_SHIFT)) {
int cpu = smp_processor_id();
local_irq_disable();
if (!in_irq())
get_irqlock(cpu);
}
}
void __global_sti(void)
{
if (!in_irq())
release_irqlock(smp_processor_id());
local_irq_enable();
}
/*
* SMP flags value to restore to:
* 0 - global cli
* 1 - global sti
* 2 - local cli
* 3 - local sti
*/
unsigned long __global_save_flags(void)
{
int retval;
int local_enabled;
unsigned long flags;
local_save_flags(flags);
local_enabled = (flags >> EFLAGS_I_SHIFT) & 1;
/* default to local */
retval = 2 + local_enabled;
/* check for global flags if we're not in an interrupt */
if (!in_irq())
{
if (local_enabled)
retval = 1;
if (atomic_read(&global_irq_holder)== smp_processor_id())
retval = 0;
}
return retval;
}
void __global_restore_flags(unsigned long flags)
{
switch (flags) {
case 0:
__global_cli();
break;
case 1:
__global_sti();
break;
case 2:
local_irq_disable();
break;
case 3:
local_irq_enable();
break;
default:
printk("global_restore_flags: %08lx (%08lx)\n",
flags, (&flags)[-1]);
}
}
#endif
void __init init_IRQ(void)
{
s390_init_IRQ();
}
void free_irq(unsigned int irq, void *dev_id)
{
s390_free_irq( irq, dev_id);
}
int request_irq( unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
const char *devname,
void *dev_id)
{
return( s390_request_irq( irq, handler, irqflags, devname, dev_id ) );
}
void init_irq_proc(void)
{
/* For now, nothing... */
}
#ifdef CONFIG_SMP
EXPORT_SYMBOL(__global_cli);
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
EXPORT_SYMBOL(global_irq_holder);
EXPORT_SYMBOL(global_irq_lock);
EXPORT_SYMBOL(global_irq_count);
EXPORT_SYMBOL(global_bh_count);
#endif
EXPORT_SYMBOL(global_bh_lock);
......@@ -514,16 +514,15 @@ static int do_sys32_msgsnd (int first, int second, int third, void *uptr)
if (!p)
return -ENOMEM;
err = -EINVAL;
if (second > MSGMAX || first < 0 || second < 0)
return -EINVAL;
goto out;
err = -EFAULT;
if (!uptr)
goto out;
err = get_user (p->mtype, &up->mtype);
err |= __copy_from_user (p->mtext, &up->mtext, second);
if (err)
if (get_user (p->mtype, &up->mtype) ||
__copy_from_user (p->mtext, &up->mtext, second))
goto out;
old_fs = get_fs ();
set_fs (KERNEL_DS);
......@@ -1953,15 +1952,17 @@ sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo,
return -EINVAL;
}
spin_lock_irq(&current->sigmask_lock);
sig = dequeue_signal(&these, &info);
spin_lock_irq(&current->sig->siglock);
sig = dequeue_signal(&current->sig->shared_pending, &these, &info);
if (!sig)
sig = dequeue_signal(&current->pending, &these, &info);
if (!sig) {
/* None ready -- temporarily unblock those we're interested
in so that we'll be awakened when they arrive. */
sigset_t oldblocked = current->blocked;
current->real_blocked = current->blocked;
sigandsets(&current->blocked, &current->blocked, &these);
recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock);
spin_unlock_irq(&current->sig->siglock);
timeout = MAX_SCHEDULE_TIMEOUT;
if (uts)
......@@ -1971,12 +1972,15 @@ sys32_rt_sigtimedwait(sigset_t32 *uthese, siginfo_t32 *uinfo,
current->state = TASK_INTERRUPTIBLE;
timeout = schedule_timeout(timeout);
spin_lock_irq(&current->sigmask_lock);
sig = dequeue_signal(&these, &info);
current->blocked = oldblocked;
spin_lock_irq(&current->sig->siglock);
sig = dequeue_signal(&current->sig->shared_pending, &these, &info);
if (!sig)
sig = dequeue_signal(&current->pending, &these, &info);
current->blocked = current->real_blocked;
siginitset(&current->real_blocked, 0);
recalc_sigpending();
}
spin_unlock_irq(&current->sigmask_lock);
spin_unlock_irq(&current->sig->siglock);
if (sig) {
ret = sig;
......@@ -3988,13 +3992,13 @@ extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char * buf,
typedef __kernel_ssize_t32 ssize_t32;
asmlinkage ssize_t32 sys32_pread(unsigned int fd, char *ubuf,
asmlinkage ssize_t32 sys32_pread64(unsigned int fd, char *ubuf,
__kernel_size_t32 count, u32 poshi, u32 poslo)
{
return sys_pread64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
}
asmlinkage ssize_t32 sys32_pwrite(unsigned int fd, char *ubuf,
asmlinkage ssize_t32 sys32_pwrite64(unsigned int fd, char *ubuf,
__kernel_size_t32 count, u32 poshi, u32 poslo)
{
return sys_pwrite64(fd, ubuf, count, ((loff_t)AA(poshi) << 32) | AA(poslo));
......@@ -4522,3 +4526,34 @@ asmlinkage int sys32_sched_getaffinity(__kernel_pid_t32 pid, unsigned int len,
return ret;
}
asmlinkage int
sys_futex(void *uaddr, int op, int val, struct timespec *utime);
asmlinkage int
sys32_futex(void *uaddr, int op, int val,
struct timespec32 *timeout32)
{
long ret;
struct timespec tmp, *timeout;
ret = -ENOMEM;
timeout = kmalloc(sizeof(*timeout), GFP_USER);
if (!timeout)
goto out;
ret = -EINVAL;
if (get_user (tmp.tv_sec, &timeout32->tv_sec) ||
get_user (tmp.tv_nsec, &timeout32->tv_nsec) ||
put_user (tmp.tv_sec, &timeout->tv_sec) ||
put_user (tmp.tv_nsec, &timeout->tv_nsec))
goto out_free;
ret = sys_futex(uaddr, op, val, timeout);
out_free:
kfree(timeout);
out:
return ret;
}
......@@ -8,8 +8,6 @@
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/export.h>
#ifdef CONFIG_S390_SUPPORT
/* Macro that masks the high order bit of an 32 bit pointer and converts it*/
/* to a 64 bit pointer */
#define A(__x) ((unsigned long)((__x) & 0x7FFFFFFFUL))
......@@ -194,6 +192,32 @@ typedef struct
__u32 addr;
} _psw_t32 __attribute__ ((aligned(8)));
#define PSW32_MASK_PER 0x40000000UL
#define PSW32_MASK_DAT 0x04000000UL
#define PSW32_MASK_IO 0x02000000UL
#define PSW32_MASK_EXT 0x01000000UL
#define PSW32_MASK_KEY 0x00F00000UL
#define PSW32_MASK_MCHECK 0x00040000UL
#define PSW32_MASK_WAIT 0x00020000UL
#define PSW32_MASK_PSTATE 0x00010000UL
#define PSW32_MASK_ASC 0x0000C000UL
#define PSW32_MASK_CC 0x00003000UL
#define PSW32_MASK_PM 0x00000f00UL
#define PSW32_ADDR_AMODE31 0x80000000UL
#define PSW32_ADDR_INSN 0x7FFFFFFFUL
#define PSW32_BASE_BITS 0x00080000UL
#define PSW32_ASC_PRIMARY 0x00000000UL
#define PSW32_ASC_ACCREG 0x00004000UL
#define PSW32_ASC_SECONDARY 0x00008000UL
#define PSW32_ASC_HOME 0x0000C000UL
#define PSW32_USER_BITS (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \
PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \
PSW32_MASK_PSTATE)
typedef struct
{
_psw_t32 psw;
......@@ -241,6 +265,4 @@ struct ucontext32 {
sigset_t32 uc_sigmask; /* mask last for extensibility */
};
#endif /* !CONFIG_S390_SUPPORT */
#endif /* _ASM_S390X_S390_H */
......@@ -15,9 +15,6 @@
* This file handles the architecture-dependent parts of process handling..
*/
#define __KERNEL_SYSCALLS__
#include <stdarg.h>
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
......@@ -78,9 +75,10 @@ void default_idle(void)
/*
* Wait for external, I/O or machine check interrupt and
* switch of machine check bit after the wait has ended.
* switch off machine check bit after the wait has ended.
*/
wait_psw.mask = _WAIT_PSW_MASK;
wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT |
PSW_MASK_IO | PSW_MASK_EXT;
asm volatile (
" larl %0,0f\n"
" stg %0,8(%1)\n"
......@@ -114,35 +112,39 @@ void show_regs(struct pt_regs *regs)
show_registers(regs);
/* Show stack backtrace if pt_regs is from kernel mode */
if (!(regs->psw.mask & PSW_PROBLEM_STATE))
if (!(regs->psw.mask & PSW_MASK_PSTATE))
show_trace((unsigned long *) regs->gprs[15]);
}
extern void kernel_thread_starter(void);
__asm__(".align 4\n"
"kernel_thread_starter:\n"
" lg 15,0(8)\n"
" sgr 15,7\n"
" stosm 48(15),3\n"
" lgr 2,10\n"
" basr 14,9\n"
" sgr 2,2\n"
" br 11\n");
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
int clone_arg = flags | CLONE_VM;
int retval;
__asm__ __volatile__(
" slgr 2,2\n"
" lgr 3,%1\n"
" lg 4,%6\n" /* load kernel stack ptr of parent */
" svc %b2\n" /* Linux system call*/
" clg 4,%6\n" /* compare ksp's: child or parent ? */
" je 0f\n" /* parent - jump*/
" lg 15,%6\n" /* fix kernel stack pointer*/
" aghi 15,%7\n"
" xc 0(160,15),0(15)\n" /* clear save area */
" lgr 2,%4\n" /* load argument*/
" basr 14,%5\n" /* call fn*/
" svc %b3\n" /* Linux system call*/
"0: lgr %0,2"
: "=a" (retval)
: "d" (clone_arg), "i" (__NR_clone), "i" (__NR_exit),
"d" (arg), "a" (fn), "i" (__LC_KERNEL_STACK) ,
"i" (-STACK_FRAME_OVERHEAD)
: "2", "3", "4" );
return retval;
struct task_struct *p;
struct pt_regs regs;
memset(&regs, 0, sizeof(regs));
regs.psw.mask = PSW_KERNEL_BITS;
regs.psw.addr = (__u64) kernel_thread_starter;
regs.gprs[7] = STACK_FRAME_OVERHEAD;
regs.gprs[8] = __LC_KERNEL_STACK;
regs.gprs[9] = (unsigned long) fn;
regs.gprs[10] = (unsigned long) arg;
regs.gprs[11] = (unsigned long) do_exit;
regs.orig_gpr2 = -1;
/* Ok, create the new process.. */
p = do_fork(flags | CLONE_VM, 0, &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
/*
......@@ -184,17 +186,20 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
(THREAD_SIZE + (unsigned long) p->thread_info)) - 1;
p->thread.ksp = (unsigned long) frame;
frame->childregs = *regs;
frame->childregs.gprs[2] = 0; /* child returns 0 on fork. */
frame->childregs.gprs[15] = new_stackp;
frame->back_chain = frame->eos = 0;
/* new return point is ret_from_sys_call */
frame->gprs[8] = (unsigned long) &ret_from_fork;
/* new return point is ret_from_fork */
frame->gprs[8] = (unsigned long) ret_from_fork;
/* fake return stack for resume(), don't go back to schedule */
frame->gprs[9] = (unsigned long) frame;
/* save fprs, if used in last task */
/* save fprs */
save_fp_regs(&p->thread.fp_regs);
p->thread.user_seg = __pa((unsigned long) p->mm->pgd) | _REGION_TABLE;
/* start new process with ar4 pointing to the correct address space */
p->thread.ar4 = get_fs().ar4;
/* Don't copy debug registers */
memset(&p->thread.per_info,0,sizeof(p->thread.per_info));
return 0;
......@@ -203,7 +208,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long new_stackp,
asmlinkage int sys_fork(struct pt_regs regs)
{
struct task_struct *p;
p = do_fork(SIGCHLD, regs.gprs[15], &regs, 0);
p = do_fork(SIGCHLD, regs.gprs[15], &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......@@ -212,12 +217,14 @@ asmlinkage int sys_clone(struct pt_regs regs)
unsigned long clone_flags;
unsigned long newsp;
struct task_struct *p;
int *user_tid;
clone_flags = regs.gprs[3];
newsp = regs.orig_gpr2;
user_tid = (int *) regs.gprs[4];
if (!newsp)
newsp = regs.gprs[15];
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0);
p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, user_tid);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......@@ -234,7 +241,8 @@ asmlinkage int sys_clone(struct pt_regs regs)
asmlinkage int sys_vfork(struct pt_regs regs)
{
struct task_struct *p;
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.gprs[15], &regs, 0);
p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
regs.gprs[15], &regs, 0, NULL);
return IS_ERR(p) ? PTR_ERR(p) : p->pid;
}
......@@ -250,15 +258,12 @@ asmlinkage int sys_execve(struct pt_regs regs)
error = PTR_ERR(filename);
if (IS_ERR(filename))
goto out;
error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], &regs);
if (error == 0)
{
error = do_execve(filename, (char **) regs.gprs[3],
(char **) regs.gprs[4], &regs);
if (error == 0) {
current->ptrace &= ~PT_DTRACE;
current->thread.fp_regs.fpc=0;
__asm__ __volatile__
("sr 0,0\n\t"
"sfpc 0,0\n\t"
: : :"0");
current->thread.fp_regs.fpc = 0;
asm volatile("sfpc %0,%0" : : "d" (0));
}
putname(filename);
out:
......@@ -285,15 +290,15 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
dump->magic = CMAGIC;
dump->start_code = 0;
dump->start_stack = regs->gprs[15] & ~(PAGE_SIZE - 1);
dump->u_tsize = ((unsigned long) current->mm->end_code) >> PAGE_SHIFT;
dump->u_dsize = ((unsigned long) (current->mm->brk + (PAGE_SIZE-1))) >> PAGE_SHIFT;
dump->u_tsize = current->mm->end_code >> PAGE_SHIFT;
dump->u_dsize = (current->mm->brk + PAGE_SIZE - 1) >> PAGE_SHIFT;
dump->u_dsize -= dump->u_tsize;
dump->u_ssize = 0;
if (dump->start_stack < TASK_SIZE)
dump->u_ssize = ((unsigned long) (TASK_SIZE - dump->start_stack)) >> PAGE_SHIFT;
memcpy(&dump->regs.gprs[0],regs,sizeof(s390_regs));
dump->u_ssize = (TASK_SIZE - dump->start_stack) >> PAGE_SHIFT;
memcpy(&dump->regs, regs, sizeof(s390_regs));
dump_fpu (regs, &dump->regs.fp_regs);
memcpy(&dump->regs.per_info,&current->thread.per_info,sizeof(per_struct));
dump->regs.per_info = current->thread.per_info;
}
/*
......
This diff is collapsed.
#ifndef _PTRACE32_H
#define _PTRACE32_H
#include "linux32.h" /* needed for _psw_t32 */
typedef struct
{
__u32 cr[3];
} per_cr_words32 __attribute__((packed));
typedef struct
{
__u16 perc_atmid; /* 0x096 */
__u32 address; /* 0x098 */
__u8 access_id; /* 0x0a1 */
} per_lowcore_words32 __attribute__((packed));
typedef struct
{
union {
per_cr_words32 words;
} control_regs __attribute__((packed));
/*
* Use these flags instead of setting em_instruction_fetch
* directly they are used so that single stepping can be
* switched on & off while not affecting other tracing
*/
unsigned single_step : 1;
unsigned instruction_fetch : 1;
unsigned : 30;
/*
* These addresses are copied into cr10 & cr11 if single
* stepping is switched off
*/
__u32 starting_addr;
__u32 ending_addr;
union {
per_lowcore_words32 words;
} lowcore;
} per_struct32 __attribute__((packed));
struct user_regs_struct32
{
_psw_t32 psw;
u32 gprs[NUM_GPRS];
u32 acrs[NUM_ACRS];
u32 orig_gpr2;
s390_fp_regs fp_regs;
/*
* These per registers are in here so that gdb can modify them
* itself as there is no "official" ptrace interface for hardware
* watchpoints. This is the way intel does it.
*/
per_struct32 per_info;
u32 ieee_instruction_pointer;
/* Used to give failing instruction back to user for ieee exceptions */
};
struct user32 {
/* We start with the registers, to mimic the way that "memory"
is returned from the ptrace(3,...) function. */
struct user_regs_struct32 regs; /* Where the registers are actually stored */
/* The rest of this junk is to help gdb figure out what goes where */
u32 u_tsize; /* Text segment size (pages). */
u32 u_dsize; /* Data segment size (pages). */
u32 u_ssize; /* Stack segment size (pages). */
u32 start_code; /* Starting virtual address of text. */
u32 start_stack; /* Starting virtual address of stack area.
This is actually the bottom of the stack,
the top of the stack is always found in the
esp register. */
s32 signal; /* Signal that caused the core dump. */
u32 u_ar0; /* Used by gdb to help find the values for */
/* the registers. */
u32 magic; /* To uniquely identify a core file */
char u_comm[32]; /* User command that was responsible */
};
typedef struct
{
__u32 len;
__u32 kernel_addr;
__u32 process_addr;
} ptrace_area_emu31;
#endif /* _PTRACE32_H */
/*
* arch/s390/kernel/s390fpu.c
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
*
* s390fpu.h functions for saving & restoring the fpu state.
*
* I couldn't inline these as linux/sched.h included half the world
* & was required to at the task structure.
* & the functions were too complex to make macros from.
* ( & as usual I didn't feel like debugging inline code ).
*/
#include <linux/sched.h>
void save_fp_regs(s390_fp_regs *fpregs)
{
/*
* I don't think we can use STE here as this would load
* fp registers 0 & 2 into memory locations 0 & 1 etc.
*/
asm volatile ("STFPC 0(%0)\n\t"
"STD 0,8(%0)\n\t"
"STD 1,16(%0)\n\t"
"STD 2,24(%0)\n\t"
"STD 3,32(%0)\n\t"
"STD 4,40(%0)\n\t"
"STD 5,48(%0)\n\t"
"STD 6,56(%0)\n\t"
"STD 7,64(%0)\n\t"
"STD 8,72(%0)\n\t"
"STD 9,80(%0)\n\t"
"STD 10,88(%0)\n\t"
"STD 11,96(%0)\n\t"
"STD 12,104(%0)\n\t"
"STD 13,112(%0)\n\t"
"STD 14,120(%0)\n\t"
"STD 15,128(%0)\n\t"
:
: "a" (fpregs)
: "memory"
);
}
void restore_fp_regs(s390_fp_regs *fpregs)
{
/* If we don't mask with the FPC_VALID_MASK here
* we've got a very quick shutdown -h now command
* via a kernel specification exception.
*/
fpregs->fpc&=FPC_VALID_MASK;
asm volatile ("LFPC 0(%0)\n\t"
"LD 0,8(%0)\n\t"
"LD 1,16(%0)\n\t"
"LD 2,24(%0)\n\t"
"LD 3,32(%0)\n\t"
"LD 4,40(%0)\n\t"
"LD 5,48(%0)\n\t"
"LD 6,56(%0)\n\t"
"LD 7,64(%0)\n\t"
"LD 8,72(%0)\n\t"
"LD 9,80(%0)\n\t"
"LD 10,88(%0)\n\t"
"LD 11,96(%0)\n\t"
"LD 12,104(%0)\n\t"
"LD 13,112(%0)\n\t"
"LD 14,120(%0)\n\t"
"LD 15,128(%0)\n\t"
:
: "a" (fpregs)
: "memory"
);
}
......@@ -52,7 +52,6 @@ unsigned long machine_flags = 0;
struct { unsigned long addr, size, type; } memory_chunk[16] = { { 0 } };
#define CHUNK_READ_WRITE 0
#define CHUNK_READ_ONLY 1
__u16 boot_cpu_addr;
int cpus_initialized = 0;
unsigned long cpu_initialized = 0;
volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
......@@ -79,7 +78,7 @@ static struct resource data_resource = { "Kernel data", 0, 0 };
/*
* cpu_init() initializes state that is per-CPU.
*/
void __init cpu_init (void)
void __devinit cpu_init (void)
{
int nr = smp_processor_id();
int addr = hard_smp_processor_id();
......@@ -305,7 +304,7 @@ void __init setup_arch(char **cmdline_p)
unsigned long start_pfn, end_pfn;
static unsigned int smptrap=0;
unsigned long delay = 0;
struct _lowcore *lowcore;
struct _lowcore *lc;
int i;
if (smptrap)
......@@ -442,30 +441,32 @@ void __init setup_arch(char **cmdline_p)
/*
* Setup lowcore for boot cpu
*/
lowcore = (struct _lowcore *)
__alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0);
memset(lowcore, 0, 2*PAGE_SIZE);
lowcore->restart_psw.mask = _RESTART_PSW_MASK;
lowcore->restart_psw.addr = (addr_t) &restart_int_handler;
lowcore->external_new_psw.mask = _EXT_PSW_MASK;
lowcore->external_new_psw.addr = (addr_t) &ext_int_handler;
lowcore->svc_new_psw.mask = _SVC_PSW_MASK;
lowcore->svc_new_psw.addr = (addr_t) &system_call;
lowcore->program_new_psw.mask = _PGM_PSW_MASK;
lowcore->program_new_psw.addr = (addr_t) &pgm_check_handler;
lowcore->mcck_new_psw.mask = _MCCK_PSW_MASK;
lowcore->mcck_new_psw.addr = (addr_t) &mcck_int_handler;
lowcore->io_new_psw.mask = _IO_PSW_MASK;
lowcore->io_new_psw.addr = (addr_t) &io_int_handler;
lowcore->ipl_device = S390_lowcore.ipl_device;
lowcore->kernel_stack = ((__u64) &init_thread_union) + 16384;
lowcore->async_stack = (__u64)
lc = (struct _lowcore *) __alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0);
memset(lc, 0, 2*PAGE_SIZE);
lc->restart_psw.mask = PSW_BASE_BITS;
lc->restart_psw.addr = (addr_t) &restart_int_handler;
lc->external_new_psw.mask = PSW_KERNEL_BITS;
lc->external_new_psw.addr = (addr_t) &ext_int_handler;
lc->svc_new_psw.mask = PSW_KERNEL_BITS;
lc->svc_new_psw.addr = (addr_t) &system_call;
lc->program_new_psw.mask = PSW_KERNEL_BITS;
lc->program_new_psw.addr = (addr_t) &pgm_check_handler;
lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
lc->mcck_new_psw.addr = (addr_t) &mcck_int_handler;
lc->io_new_psw.mask = PSW_KERNEL_BITS;
lc->io_new_psw.addr = (addr_t) &io_int_handler;
lc->ipl_device = S390_lowcore.ipl_device;
lc->kernel_stack = ((__u64) &init_thread_union) + 16384;
lc->async_stack = (__u64)
__alloc_bootmem(4*PAGE_SIZE, 4*PAGE_SIZE, 0) + 16384;
lowcore->jiffy_timer = -1LL;
set_prefix((__u32)(__u64) lowcore);
lc->jiffy_timer = -1LL;
if (MACHINE_HAS_DIAG44)
lc->diag44_opcode = 0x83000044;
else
lc->diag44_opcode = 0x07000700;
set_prefix((__u32)(__u64) lc);
cpu_init();
boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr;
__cpu_logical_map[0] = boot_cpu_addr;
__cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
/*
* Create kernel page tables and switch to virtual addressing.
......@@ -514,11 +515,14 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "vendor_id : IBM/S390\n"
"# processors : %i\n"
"bogomips per cpu: %lu.%02lu\n",
smp_num_cpus, loops_per_jiffy/(500000/HZ),
num_online_cpus(), loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ))%100);
}
if (cpu_online_map & (1 << n)) {
cpuinfo = &safe_get_cpu_lowcore(n)->cpu_data;
if (smp_processor_id() == n)
cpuinfo = &S390_lowcore.cpu_data;
else
cpuinfo = &lowcore_ptr[n]->cpu_data;
seq_printf(m, "processor %li: "
"version = %02X, "
"identification = %06X, "
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -6,8 +6,7 @@ L_TARGET = lib.a
EXTRA_AFLAGS := -traditional
obj-y = checksum.o delay.o memset.o misaligned.o strcmp.o strncpy.o uaccess.o
export-objs += misaligned.o
obj-y = delay.o memset.o strcmp.o strncpy.o uaccess.o
include $(TOPDIR)/Rules.make
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -7,6 +7,9 @@ export-objs := s390dyn.o qdio.o
obj-$(CONFIG_QDIO) += qdio.o
obj-y += s390mach.o s390dyn.o sysinfo.o
obj-y += block/ char/ misc/ net/ cio/
obj-y += cio/ block/ char/ misc/ net/
drivers-y += drivers/s390/built-in.o
include $(TOPDIR)/Rules.make
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -234,7 +234,7 @@ typedef struct tub_s {
enum tubstat stat;
enum tubcmd cmd;
int flags; /* See below for values */
struct tq_struct tqueue;
struct tasklet_struct tasklet;
/* Stuff for fs-driver support */
pid_t fs_pid; /* Pid if TBM_FS */
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment