diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2001-03-09 20:33:35 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2001-03-09 20:33:35 +0000 |
commit | 116674acc97ba75a720329996877077d988443a2 (patch) | |
tree | 6a3f2ff0b612ae2ee8a3f3509370c9e6333a53b3 /arch/s390 | |
parent | 71118c319fcae4a138f16e35b4f7e0a6d53ce2ca (diff) |
Merge with Linux 2.4.2.
Diffstat (limited to 'arch/s390')
45 files changed, 3563 insertions, 6367 deletions
diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 7af7bb937..3023d54a2 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -14,6 +14,7 @@ # LD=$(CROSS_COMPILE)ld -m elf_s390 +CPP=$(CC) -E OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S LDFLAGS=-e start LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux.lds $(LDFLAGS) diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile index 817152810..fb112b964 100644 --- a/arch/s390/boot/Makefile +++ b/arch/s390/boot/Makefile @@ -10,12 +10,11 @@ OBJCOPY = $(CROSS_COMPILE)objcopy O_TARGET := -O_OBJS := include $(TOPDIR)/Rules.make .S.o: - $(CC) $(AFLAGS) -traditional -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o %.lnk: %.o $(LD) -Ttext 0x0 -o $@ $< diff --git a/arch/s390/boot/ipldump.S b/arch/s390/boot/ipldump.S index 7868268af..3a09d1fea 100644 --- a/arch/s390/boot/ipldump.S +++ b/arch/s390/boot/ipldump.S @@ -38,7 +38,7 @@ _start: # # find out memory size # - mvc 104(8,0),.Lpcmem0 # setup program check handler + mvc 104(8),.Lpcmem0 # setup program check handler slr %r3,%r3 lhi %r2,1 sll %r2,20 diff --git a/arch/s390/boot/ipleckd.S b/arch/s390/boot/ipleckd.S index 63b0330b2..d66a8d684 100644 --- a/arch/s390/boot/ipleckd.S +++ b/arch/s390/boot/ipleckd.S @@ -3,7 +3,7 @@ # IPL record for 3380/3390 DASD # # S390 version -# Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation +# Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation # Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com> # # @@ -11,6 +11,8 @@ # FIXME: should insert zeroes into memory when filling holes # FIXME: calculate blkpertrack from rdc data and blksize +# change 09/20/00 removed obsolete store of ipldevice to textesegment + # Usage of registers # r1: ipl subchannel ( general use, dont overload without save/restore !) # r10: @@ -39,7 +41,7 @@ .org 0xf0 # Lets start now... _start: .globl _start - l %r1,__LC_SUBCHANNEL_ID # get IPL-subchannel from lowcore + l %r1,__LC_SUBCHANNEL_ID # get IPL-subchannel from lowcore st %r1,__LC_IPLDEV # keep it for reipl stsch .Lrdcdata oi .Lrdcdata+5,0x84 # enable ssch and multipath mode @@ -111,10 +113,10 @@ _start: .globl _start mvc 0x600(256,%r3),0x180(%r4) mvc 0x700(256,%r3),0x280(%r4) .Lrunkern: - lhi %r2,17 - sll %r2,12 - st %r1,0xc6c(%r2) # store iplsubchannel to lowcore - st %r1,0xc6c # store iplsubchannel to lowcore +# lhi %r2,17 +# sll %r2,12 +# st %r1,0xc6c(%r2) # store iplsubchannel to lowcore +# st %r1,0xc6c # store iplsubchannel to lowcore br %r3 # This function does the start IO # r2: number of first block to read ( input by caller ) @@ -140,17 +142,16 @@ _start: .globl _start lr %r15,%r4 # save number or blocks slr %r7,%r7 icm %r7,3,.Lrdcdata+14 # load heads to r7 + lhi %r6,9 + clc .Lrdcdata+3(2),.L9345 + je .L011 + lhi %r6,10 + clc .Lrdcdata+3(2),.L3380 + je .L011 + lhi %r6,12 clc .Lrdcdata+3(2),.L3390 - jne .L010 # 3380 or 3390 ? - lhi %r6,12 # setup r6 correct! - j .L011 -.L010: - clc .Lrdcdata+3(2),.L9343 - jne .L013 - lhi %r6,9 - j .L011 -.L013: - lhi %r6,10 + je .L011 + bras %r14,.Ldisab .L011: # loop for nbl times .Lrdloop: @@ -245,10 +246,13 @@ _start: .globl _start .long 0x00008000 # they are loaded with a LM .L3390: .word 0x3390 -.L9343: - .word 0x9343 +.L9345: + .word 0x9345 +.L3380: + .word 0x3380 .Lnull: .long 0x00000000,0x00000000 + .align 4 .Lrdcdata: .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 diff --git a/arch/s390/config.in b/arch/s390/config.in index 4415799ff..fc3b430a6 100644 --- a/arch/s390/config.in +++ b/arch/s390/config.in @@ -44,31 +44,20 @@ bool 'Networking support' CONFIG_NET bool 'System V IPC' CONFIG_SYSVIPC bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT bool 'Sysctl support' CONFIG_SYSCTL +define CONFIG_KCORE ELF tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF - +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG endmenu source drivers/s390/Config.in -mainmenu_option next_comment -comment 'Character devices' -bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS -if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then - int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 -fi - -endmenu - if [ "$CONFIG_NET" = "y" ]; then source net/Config.in fi source fs/Config.in -# source drivers/char/Config.in - -# source drivers/media/Config.in - mainmenu_option next_comment comment 'Kernel hacking' diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 459d51ebb..c4e590e75 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -1,6 +1,9 @@ # # Automatically generated by make menuconfig: don't edit # +# CONFIG_ISA is not set +# CONFIG_EISA is not set +# CONFIG_MCA is not set CONFIG_UID16=y CONFIG_ARCH_S390=y @@ -20,7 +23,7 @@ CONFIG_IEEEFPU_EMULATION=y # CONFIG_MODULES=y # CONFIG_MODVERSIONS is not set -# CONFIG_KMOD is not set +CONFIG_KMOD=y # # General setup @@ -34,41 +37,60 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PROCESS_DEBUG is not set # -# S/390 block device drivers +# Block device drivers # CONFIG_BLK_DEV_LOOP=y # CONFIG_BLK_DEV_NBD is not set -# CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=24576 CONFIG_BLK_DEV_INITRD=y -# CONFIG_MDISK is not set +CONFIG_BLK_DEV_XPRAM=m CONFIG_DASD=y CONFIG_DASD_ECKD=y -# CONFIG_DASD_MDSK is not set +CONFIG_DASD_FBA=y # -# S/390 Network device support +# Multi-device support (RAID and LVM) # -# CONFIG_CHANDEV is not set -CONFIG_NETDEVICES=y -CONFIG_CTC=y -CONFIG_IUCV=y -# CONFIG_DUMMY is not set -CONFIG_NET_ETHERNET=y -CONFIG_TR=y -# CONFIG_FDDI is not set +CONFIG_MD=y +CONFIG_BLK_DEV_MD=m +# CONFIG_MD_LINEAR is not set +CONFIG_MD_RAID0=m +CONFIG_MD_RAID1=m +CONFIG_MD_RAID5=m +CONFIG_BLK_DEV_LVM=m +CONFIG_LVM_PROC_FS=y # -# S/390 Terminal and Console options +# Character device drivers # +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=256 CONFIG_3215=y CONFIG_3215_CONSOLE=y CONFIG_HWC=y CONFIG_HWC_CONSOLE=y -CONFIG_UNIX98_PTYS=y -CONFIG_UNIX98_PTY_COUNT=256 +CONFIG_S390_TAPE=m +CONFIG_S390_TAPE_CHAR=y +CONFIG_S390_TAPE_BLOCK=y +CONFIG_S390_TAPE_3490=y +CONFIG_S390_TAPE_3480=y + +# +# Network device drivers +# +CONFIG_NETDEVICES=y +# CONFIG_DUMMY is not set +CONFIG_NET_ETHERNET=y +CONFIG_TR=y +# CONFIG_FDDI is not set +# CONFIG_CHANDEV is not set +CONFIG_CTC=m +CONFIG_IUCV=m # # Networking options @@ -82,25 +104,24 @@ CONFIG_NETLINK=y # CONFIG_FILTER is not set CONFIG_UNIX=y CONFIG_INET=y -# CONFIG_IP_MULTICAST is not set +CONFIG_IP_MULTICAST=y # CONFIG_IP_ADVANCED_ROUTER is not set # CONFIG_IP_PNP is not set -# CONFIG_IP_ROUTER is not set # CONFIG_NET_IPIP is not set # CONFIG_NET_IPGRE is not set -# CONFIG_IP_ALIAS is not set +# CONFIG_INET_ECN is not set # CONFIG_SYN_COOKIES is not set -CONFIG_SKB_LARGE=y # CONFIG_IPV6 is not set # CONFIG_KHTTPD is not set # CONFIG_ATM is not set # CONFIG_IPX is not set # CONFIG_ATALK is not set # CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set # CONFIG_X25 is not set # CONFIG_LAPB is not set -# CONFIG_BRIDGE 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 # CONFIG_NET_FASTROUTE is not set @@ -118,6 +139,7 @@ CONFIG_SKB_LARGE=y # CONFIG_AUTOFS_FS is not set # CONFIG_AUTOFS4_FS is not set # CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set # CONFIG_AFFS_FS is not set # CONFIG_HFS_FS is not set # CONFIG_BFS_FS is not set @@ -126,28 +148,37 @@ CONFIG_SKB_LARGE=y # CONFIG_UMSDOS_FS is not set # CONFIG_VFAT_FS is not set # CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set # CONFIG_CRAMFS is not set +# CONFIG_RAMFS is not set # CONFIG_ISO9660_FS is not set # CONFIG_JOLIET is not set # CONFIG_MINIX_FS is not set # CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set # CONFIG_DEVPTS_FS is not set # CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set # CONFIG_ROMFS_FS is not set CONFIG_EXT2_FS=y # CONFIG_SYSV_FS is not set +# CONFIG_SYSV_FS_WRITE is not set # CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set # CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set # # Network File Systems # # CONFIG_CODA_FS is not set CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y # CONFIG_NFSD_V3 is not set @@ -155,6 +186,16 @@ CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_MOUNT_SUBDIR is not set +# CONFIG_NCPFS_NDS_DOMAINS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set # # Partition Types @@ -168,10 +209,10 @@ CONFIG_IBM_PARTITION=y # CONFIG_MAC_PARTITION is not set # CONFIG_MSDOS_PARTITION is not set # CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set # CONFIG_SUN_PARTITION is not set # CONFIG_NLS is not set # # Kernel hacking # -# CONFIG_REMOTE_DEBUG is not set diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index f04b1cd74..dfaadc490 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -8,47 +8,25 @@ # Note 2! The CFLAGS definitions are now in the main makefile... .S.o: - $(CC) $(AFLAGS) -traditional -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o all: kernel.o head.o init_task.o O_TARGET := kernel.o -O_OBJS := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \ + +export-objs := s390_ksyms.o +obj-y := lowcore.o entry.o bitmap.o traps.o time.o process.o irq.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - semaphore.o s390fpu.o s390io.o s390mach.o s390dyn.o reipl.o -OX_OBJS := s390_ksyms.o -MX_OBJS := - -ifdef CONFIG_SMP -O_OBJS += smp.o -endif - -ifdef CONFIG_PCI -O_OBJS += bios32.o -endif - -ifdef CONFIG_MCA -O_OBJS += mca.o -endif - -ifeq ($(CONFIG_MTRR),y) -OX_OBJS += mtrr.o -else - ifeq ($(CONFIG_MTRR),m) - MX_OBJS += mtrr.o - endif -endif - -ifeq ($(CONFIG_IEEEFPU_EMULATION),y) - O_OBJS += mathemu.o floatlib.o -endif + semaphore.o s390fpu.o reipl.o s390_ext.o debug.o + +obj-$(CONFIG_MODULES) += s390_ksyms.o +obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_IEEEFPU_EMULATION) += mathemu.o floatlib.o # # Kernel debugging # -ifdef CONFIG_REMOTE_DEBUG -O_OBJS += gdb-stub.o #gdb-low.o -endif +obj-$(CONFIG_REMOTE_DEBUG) += gdb-stub.o #gdb-low.o include $(TOPDIR)/Rules.make diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 818958b4f..68abd7d50 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -8,7 +8,7 @@ #include <linux/stddef.h> #include <linux/kernel.h> -#include <asm/string.h> +#include <linux/string.h> #include <asm/ebcdic.h> void cpcmd(char *cmd, char *response, int rlen) @@ -22,10 +22,10 @@ void cpcmd(char *cmd, char *response, int rlen) ASCEBC(obuffer,olen); if (response != NULL && rlen > 0) { - asm volatile ("LRA 2,0(0,%0)\n\t" + asm volatile ("LRA 2,0(%0)\n\t" "LR 4,%1\n\t" "O 4,%4\n\t" - "LRA 3,0(0,%2)\n\t" + "LRA 3,0(%2)\n\t" "LR 5,%3\n\t" ".long 0x83240008 # Diagnose 83\n\t" : /* no output */ @@ -34,7 +34,7 @@ void cpcmd(char *cmd, char *response, int rlen) : "2", "3", "4", "5" ); EBCASC(response, rlen); } else { - asm volatile ("LRA 2,0(0,%0)\n\t" + asm volatile ("LRA 2,0(%0)\n\t" "LR 3,%1\n\t" ".long 0x83230008 # Diagnose 83\n\t" : /* no output */ diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c new file mode 100644 index 000000000..bb3dfe5de --- /dev/null +++ b/arch/s390/kernel/debug.c @@ -0,0 +1,1167 @@ +/* + * arch/s390/kernel/debug.c + * S/390 debug facility + * + * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, + * IBM Corporation + * Author(s): Michael Holzheu (holzheu@de.ibm.com), + * Holger Smolinski (Holger.Smolinski@de.ibm.com) + * + * Bugreports to: <Linux390@de.ibm.com> + */ + +#include <linux/config.h> +#include <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/malloc.h> +#include <linux/vmalloc.h> +#include <linux/ctype.h> +#include <linux/version.h> +#include <asm/uaccess.h> +#include <asm/semaphore.h> + +#ifdef MODULE +#include <linux/module.h> +#endif + +#include <asm/debug.h> + +#define MIN(a,b) (((a)<(b))?(a):(b)) + +#if defined(CONFIG_ARCH_S390X) +#define DEBUG_PROC_HEADER_SIZE 46 +#else +#define DEBUG_PROC_HEADER_SIZE 38 +#endif + +#define ADD_BUFFER 1000 + +/* typedefs */ + +typedef struct file_private_info { + loff_t len; /* length of output in byte */ + int size; /* size of buffer for output */ + char *data; /* buffer for output */ + debug_info_t *debug_info; /* the debug information struct */ + struct debug_view *view; /* used view of debug info */ +} file_private_info_t; + +extern void tod_to_timeval(uint64_t todval, struct timeval *xtime); + +/* internal function prototyes */ + +static int debug_init(void); +static int debug_format_output(debug_info_t * debug_area, char *buf, + int size, struct debug_view *view); +static ssize_t debug_output(struct file *file, char *user_buf, + size_t user_len, loff_t * offset); +static ssize_t debug_input(struct file *file, const char *user_buf, + size_t user_len, loff_t * offset); +static int debug_open(struct inode *inode, struct file *file); +static int debug_close(struct inode *inode, struct file *file); +static struct proc_dir_entry +*debug_create_proc_dir_entry(struct proc_dir_entry *root, + const char *name, mode_t mode, + struct inode_operations *iops, + struct file_operations *fops); +static void debug_delete_proc_dir_entry(struct proc_dir_entry *root, + struct proc_dir_entry *entry); +static debug_info_t* debug_info_create(char *name, int page_order, int nr_areas, int buf_size); +static void debug_info_get(debug_info_t *); +static void debug_info_put(debug_info_t *); +static int debug_prolog_level_fn(debug_info_t * id, + struct debug_view *view, char *out_buf); +static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, + struct file *file, const char *user_buf, + size_t user_buf_size, loff_t * offset); +static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf); +static int debug_raw_format_fn(debug_info_t * id, + struct debug_view *view, char *out_buf, + const char *in_buf); +static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, + int area, debug_entry_t * entry, char *out_buf); + +/* globals */ + +struct debug_view debug_raw_view = { + "raw", + NULL, + &debug_raw_header_fn, + &debug_raw_format_fn, + NULL +}; + +struct debug_view debug_hex_ascii_view = { + "hex_ascii", + NULL, + &debug_dflt_header_fn, + &debug_hex_ascii_format_fn, + NULL +}; + +struct debug_view debug_level_view = { + "level", + &debug_prolog_level_fn, + NULL, + NULL, + &debug_input_level_fn +}; + +/* static globals */ + +static debug_info_t *debug_area_first = NULL; +static debug_info_t *debug_area_last = NULL; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) +static struct semaphore debug_lock = MUTEX; +#else +DECLARE_MUTEX(debug_lock); +#endif + +static int initialized = 0; + +static struct file_operations debug_file_ops = { + read: debug_output, + write: debug_input, + open: debug_open, + release: debug_close, +}; + +static struct inode_operations debug_inode_ops = { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) + default_file_ops: &debug_file_ops, /* file ops */ +#endif +}; + + +static struct proc_dir_entry *debug_proc_root_entry; + + +/* functions */ + +/* + * debug_info_create + * - create new debug-info + */ + +static debug_info_t* debug_info_create(char *name, int page_order, + int nr_areas, int buf_size) +{ + debug_info_t* rc; + int i; + + /* alloc everything */ + + rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC); + if(!rc) + goto fail_malloc_rc; + rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC); + if(!rc->active_entry) + goto fail_malloc_active_entry; + memset(rc->active_entry, 0, nr_areas * sizeof(int)); + rc->areas = (debug_entry_t **) kmalloc(nr_areas * + sizeof(debug_entry_t *), + GFP_ATOMIC); + if (!rc->areas) + goto fail_malloc_areas; + for (i = 0; i < nr_areas; i++) { + rc->areas[i] = + (debug_entry_t *) __get_free_pages(GFP_ATOMIC, + page_order); + if (!rc->areas[i]) { + for (i--; i >= 0; i--) { + free_pages((unsigned long) rc->areas[i], + page_order); + } + goto fail_malloc_areas2; + } else { + memset(rc->areas[i], 0, PAGE_SIZE << page_order); + } + } + + /* initialize members */ + + spin_lock_init(&rc->lock); + rc->page_order = page_order; + rc->nr_areas = nr_areas; + rc->active_area = 0; + rc->level = DEBUG_DEFAULT_LEVEL; + rc->buf_size = buf_size; + rc->entry_size = sizeof(debug_entry_t) + buf_size; + strncpy(rc->name, name, MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))); + rc->name[MIN(strlen(name), (DEBUG_MAX_PROCF_LEN - 1))] = 0; + memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *)); + memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS * + sizeof(struct proc_dir_entry*)); + atomic_set(&(rc->ref_count), 0); + rc->proc_root_entry = + debug_create_proc_dir_entry(debug_proc_root_entry, rc->name, + S_IFDIR | S_IRUGO | S_IXUGO | + S_IWUSR | S_IWGRP, NULL, NULL); + + /* append new element to linked list */ + + if(debug_area_first == NULL){ + /* first element in list */ + debug_area_first = rc; + rc->prev = NULL; + } + else{ + /* append element to end of list */ + debug_area_last->next = rc; + rc->prev = debug_area_last; + } + debug_area_last = rc; + rc->next = NULL; + + debug_info_get(rc); + return rc; + +fail_malloc_areas2: + kfree(rc->areas); +fail_malloc_areas: + kfree(rc->active_entry); +fail_malloc_active_entry: + kfree(rc); +fail_malloc_rc: + return NULL; +} + +/* + * debug_info_get + * - increments reference count for debug-info + */ + +static void debug_info_get(debug_info_t * db_info) +{ + if (db_info) + atomic_inc(&db_info->ref_count); +} + +/* + * debug_info_put: + * - decreases reference count for debug-info and frees it if necessary + */ + +static void debug_info_put(debug_info_t *db_info) +{ + int i; + + if (!db_info) + return; + if (atomic_dec_and_test(&db_info->ref_count)) { + printk(KERN_INFO "debug: freeing debug area %p (%s)\n", + db_info, db_info->name); + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (db_info->views[i] != NULL) + debug_delete_proc_dir_entry + (db_info->proc_root_entry, + db_info->proc_entries[i]); + } + debug_delete_proc_dir_entry(debug_proc_root_entry, + db_info->proc_root_entry); + for (i = 0; i < db_info->nr_areas; i++) { + free_pages((unsigned long) db_info->areas[i], + db_info->page_order); + } + kfree(db_info->areas); + kfree(db_info->active_entry); + if(db_info == debug_area_first) + debug_area_first = db_info->next; + if(db_info == debug_area_last) + debug_area_last = db_info->prev; + if(db_info->prev) db_info->prev->next = db_info->next; + if(db_info->next) db_info->next->prev = db_info->prev; + kfree(db_info); + } +} + + +/* + * debug_output: + * - called for user read() + * - copies formated output form private_data of the file + * handle to the user buffer + */ + +static ssize_t debug_output(struct file *file, /* file descriptor */ + char *user_buf, /* user buffer */ + size_t user_len, /* length of buffer */ + loff_t *offset /* offset in the file */ ) +{ + loff_t len; + int rc; + file_private_info_t *p_info; + + p_info = ((file_private_info_t *) file->private_data); + if (*offset >= p_info->len) { + return 0; /* EOF */ + } else { + len = MIN(user_len, (p_info->len - *offset)); + if ((rc = copy_to_user(user_buf, &(p_info->data[*offset]),len))) + return rc;; + (*offset) += len; + return len; /* number of bytes "read" */ + } +} + +/* + * debug_input: + * - called for user write() + * - calls input function of view + */ + +static ssize_t debug_input(struct file *file, + const char *user_buf, size_t length, + loff_t *offset) +{ + int rc = 0; + file_private_info_t *p_info; + + down(&debug_lock); + p_info = ((file_private_info_t *) file->private_data); + if (p_info->view->input_proc) + rc = p_info->view->input_proc(p_info->debug_info, + p_info->view, file, user_buf, + length, offset); + up(&debug_lock); + return rc; /* number of input characters */ +} + +/* + * debug_format_output: + * - calls prolog, header and format functions of view to format output + */ + +static int debug_format_output(debug_info_t * debug_area, char *buf, + int size, struct debug_view *view) +{ + int len = 0; + int i, j; + int nr_of_entries; + debug_entry_t *act_entry; + + /* print prolog */ + if (view->prolog_proc) + len += view->prolog_proc(debug_area, view, buf); + /* print debug records */ + if (!(view->format_proc) && !(view->header_proc)) + goto out; + nr_of_entries = PAGE_SIZE / debug_area->entry_size + << debug_area->page_order; + for (i = 0; i < debug_area->nr_areas; i++) { + act_entry = debug_area->areas[i]; + for (j = 0; j < nr_of_entries; j++) { + if (act_entry->id.fields.used == 0) + break; /* empty entry */ + if (view->header_proc) + len += view->header_proc(debug_area, view, i, + act_entry, buf + len); + if (view->format_proc) + len += view->format_proc(debug_area, view, + buf + len, + DEBUG_DATA(act_entry)); + if (len > size) { + printk(KERN_ERR + "debug: error -- memory exceeded for (%s/%s)\n", + debug_area->name, view->name); + printk(KERN_ERR "debug: fix view %s!!\n", + view->name); + printk(KERN_ERR + "debug: area: %i (0 - %i) entry: %i (0 - %i)\n", + i, debug_area->nr_areas - 1, j, + nr_of_entries - 1); + goto out; + } + act_entry = (debug_entry_t *) (((char *) act_entry) + + debug_area->entry_size); + } + } + out: + return len; +} + + +/* + * debug_open: + * - called for user open() + * - copies formated output to private_data area of the file + * handle + */ + +static int debug_open(struct inode *inode, struct file *file) +{ + int i = 0, size = 0, rc = 0, f_entry_size = 0; + file_private_info_t *p_info; + debug_info_t* debug_info; + +#ifdef DEBUG + printk("debug_open\n"); +#endif + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + down(&debug_lock); + + /* find debug log and view */ + + debug_info = debug_area_first; + while(debug_info != NULL){ + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (debug_info->views[i] == NULL) + continue; + else if (debug_info->proc_entries[i]->low_ino == + file->f_dentry->d_inode->i_ino) { + goto found; /* found view ! */ + } + } + debug_info = debug_info->next; + } + /* no entry found */ + rc = -EINVAL; + goto out; + found: + if ((file->private_data = + kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) { + printk(KERN_ERR "debug_open: kmalloc failed\n"); + rc = -ENOMEM; + goto out; + } + p_info = (file_private_info_t *) file->private_data; + + /* + * the size for the formated output is calculated + * with the following formula: + * + * prolog-size + * + + * (record header size + record data field size) + * * number of entries per page + * * number of pages per area + * * number of areas + */ + + if (debug_info->views[i]->prolog_proc) + size += + debug_info->views[i]->prolog_proc(debug_info, + debug_info-> + views[i], NULL); + + if (debug_info->views[i]->header_proc) + f_entry_size = + debug_info->views[i]->header_proc(debug_info, + debug_info-> + views[i], 0, NULL, + NULL); + if (debug_info->views[i]->format_proc) + f_entry_size += + debug_info->views[i]->format_proc(debug_info, + debug_info-> + views[i], NULL, + NULL); + + size += f_entry_size + * (PAGE_SIZE / debug_info->entry_size + << debug_info->page_order) + * debug_info->nr_areas + 1; /* terminating \0 */ +#ifdef DEBUG + printk("debug_open: size: %i\n", size); +#endif + + /* alloc some bytes more to be safe against bad views */ + if ((p_info->data = vmalloc(size + ADD_BUFFER)) == 0) { + printk(KERN_ERR "debug_open: vmalloc failed\n"); + vfree(file->private_data); + rc = -ENOMEM; + goto out; + } + + p_info->size = size; + p_info->debug_info = debug_info; + p_info->view = debug_info->views[i]; + + spin_lock_irq(&debug_info->lock); + + p_info->len = + debug_format_output(debug_info, p_info->data, size, + debug_info->views[i]); +#ifdef DEBUG + { + int ilen = p_info->len; + printk("debug_open: len: %i\n", ilen); + } +#endif + + spin_unlock_irq(&debug_info->lock); + debug_info_get(debug_info); + + out: + up(&debug_lock); +#ifdef MODULE + if (rc != 0) + MOD_DEC_USE_COUNT; +#endif + return rc; +} + +/* + * debug_close: + * - called for user close() + * - deletes private_data area of the file handle + */ + +static int debug_close(struct inode *inode, struct file *file) +{ + file_private_info_t *p_info; +#ifdef DEBUG + printk("debug_close\n"); +#endif + down(&debug_lock); + p_info = (file_private_info_t *) file->private_data; + debug_info_put(p_info->debug_info); + if (p_info->data) { + vfree(p_info->data); + kfree(file->private_data); + } + up(&debug_lock); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + return 0; /* success */ +} + +/* + * debug_create_proc_dir_entry: + * - initializes proc-dir-entry and registers it + */ + +static struct proc_dir_entry *debug_create_proc_dir_entry + (struct proc_dir_entry *root, const char *name, mode_t mode, + struct inode_operations *iops, struct file_operations *fops) +{ + struct proc_dir_entry *rc = NULL; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) + const char *fn = name; + int len; + len = strlen(fn); + + rc = (struct proc_dir_entry *) kmalloc(sizeof(struct proc_dir_entry) + + len + 1, GFP_ATOMIC); + if (!rc) + goto out; + + memset(rc, 0, sizeof(struct proc_dir_entry)); + memcpy(((char *) rc) + sizeof(*rc), fn, len + 1); + rc->name = ((char *) rc) + sizeof(*rc); + rc->namelen = len; + rc->low_ino = 0, rc->mode = mode; + rc->nlink = 1; + rc->uid = 0; + rc->gid = 0; + rc->size = 0; + rc->get_info = NULL; + rc->ops = iops; + + proc_register(root, rc); +#else + rc = create_proc_entry(name, mode, root); + if (!rc) + goto out; + if (fops) + rc->proc_fops = fops; +#endif + + out: + return rc; +} + + +/* + * delete_proc_dir_entry: + */ + +static void debug_delete_proc_dir_entry + (struct proc_dir_entry *root, struct proc_dir_entry *proc_entry) +{ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) + proc_unregister(root, proc_entry->low_ino); + kfree(proc_entry); +#else + remove_proc_entry(proc_entry->name, root); +#endif +} + +/* + * debug_register: + * - creates and initializes debug area for the caller + * - returns handle for debug area + */ + +debug_info_t *debug_register + (char *name, int page_order, int nr_areas, int buf_size) +{ + debug_info_t *rc = NULL; + +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif + if (!initialized) + debug_init(); + down(&debug_lock); + + /* create new debug_info */ + + rc = debug_info_create(name, page_order, nr_areas, buf_size); + if(!rc) + goto out; + debug_register_view(rc, &debug_level_view); + printk(KERN_INFO + "debug: reserved %d areas of %d pages for debugging %s\n", + nr_areas, 1 << page_order, rc->name); + out: + if (rc == NULL){ + printk(KERN_ERR "debug: debug_register failed for %s\n",name); +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + } + up(&debug_lock); + return rc; +} + +/* + * debug_unregister: + * - give back debug area + */ + +void debug_unregister(debug_info_t * id) +{ + if (!id) + goto out; + down(&debug_lock); + printk(KERN_INFO "debug: unregistering %s\n", id->name); + debug_info_put(id); + up(&debug_lock); + +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif + out: + return; +} + +/* + * debug_set_level: + * - set actual debug level + */ + +void debug_set_level(debug_info_t* id, int new_level) +{ + long flags; + if(!id) + return; + spin_lock_irqsave(&id->lock,flags); + if(new_level == DEBUG_OFF_LEVEL){ + id->level = DEBUG_OFF_LEVEL; + printk(KERN_INFO "debug: %s: switched off\n",id->name); + } else if ((new_level > DEBUG_MAX_LEVEL) || (new_level < 0)) { + printk(KERN_INFO + "debug: %s: level %i is out of range (%i - %i)\n", + id->name, new_level, 0, DEBUG_MAX_LEVEL); + } else { + id->level = new_level; + printk(KERN_INFO + "debug: %s: new level %i\n",id->name,id->level); + } + spin_unlock_irqrestore(&id->lock,flags); +} + + +/* + * proceed_active_entry: + * - set active entry to next in the ring buffer + */ + +static inline void proceed_active_entry(debug_info_t * id) +{ + if ((id->active_entry[id->active_area] += id->entry_size) + > ((PAGE_SIZE << (id->page_order)) - id->entry_size)) + id->active_entry[id->active_area] = 0; +} + +/* + * proceed_active_area: + * - set active area to next in the ring buffer + */ + +static inline void proceed_active_area(debug_info_t * id) +{ + id->active_area++; + id->active_area = id->active_area % id->nr_areas; +} + +/* + * get_active_entry: + */ + +static inline debug_entry_t *get_active_entry(debug_info_t * id) +{ + return (debug_entry_t *) ((char *) id->areas[id->active_area] + + id->active_entry[id->active_area]); +} + +/* + * debug_common: + * - set timestamp, caller address, cpu number etc. + */ + +static inline debug_entry_t *debug_common(debug_info_t * id) +{ + debug_entry_t *active; + + active = get_active_entry(id); + STCK(active->id.stck); + active->id.fields.cpuid = smp_processor_id(); + active->id.fields.used = 1; + active->caller = __builtin_return_address(0); + return active; +} + +/* + * debug_event: + */ + +debug_entry_t *debug_event(debug_info_t * id, int level, void *buf, + int len) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level > id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + active->id.fields.exception = 0; + memset(DEBUG_DATA(active), 0, id->buf_size); + memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); + proceed_active_entry(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; +} + +/* + * debug_int_event: + */ + +debug_entry_t *debug_int_event(debug_info_t * id, int level, + unsigned int tag) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level > id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + active->id.fields.exception = 0; + memset(DEBUG_DATA(active), 0, id->buf_size); + memcpy(DEBUG_DATA(active), &tag, MIN(sizeof(unsigned int), id->buf_size)); + proceed_active_entry(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; +} + +/* + * debug_text_event: + */ + +debug_entry_t *debug_text_event(debug_info_t * id, int level, + const char *txt) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level > id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + memset(DEBUG_DATA(active), 0, id->buf_size); + strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size)); + active->id.fields.exception = 0; + proceed_active_entry(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; + +} + +/* + * debug_exception: + */ + +debug_entry_t *debug_exception(debug_info_t * id, int level, void *buf, + int len) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level > id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + active->id.fields.exception = 1; + memset(DEBUG_DATA(active), 0, id->buf_size); + memcpy(DEBUG_DATA(active), buf, MIN(len, id->buf_size)); + proceed_active_entry(id); + proceed_active_area(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; +} + +/* + * debug_int_exception: + */ + +debug_entry_t *debug_int_exception(debug_info_t * id, int level, + unsigned int tag) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level > id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + active->id.fields.exception = 1; + memset(DEBUG_DATA(active), 0, id->buf_size); + memcpy(DEBUG_DATA(active), &tag, + MIN(sizeof(unsigned int), id->buf_size)); + proceed_active_entry(id); + proceed_active_area(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; +} + +/* + * debug_text_exception: + */ + +debug_entry_t *debug_text_exception(debug_info_t * id, int level, + const char *txt) +{ + long flags; + debug_entry_t *active = NULL; + + if ((!id) || (level > id->level)) + goto out; + spin_lock_irqsave(&id->lock, flags); + active = debug_common(id); + memset(DEBUG_DATA(active), 0, id->buf_size); + strncpy(DEBUG_DATA(active), txt, MIN(strlen(txt), id->buf_size)); + active->id.fields.exception = 1; + proceed_active_entry(id); + proceed_active_area(id); + spin_unlock_irqrestore(&id->lock, flags); + out: + return active; + +} + +/* + * debug_init: + * - is called exactly once to initialize the debug feature + */ + +int debug_init(void) +{ + int rc = 0; + + down(&debug_lock); + if (!initialized) { + debug_proc_root_entry = + debug_create_proc_dir_entry(&proc_root, DEBUG_DIR_ROOT, + S_IFDIR | S_IRUGO | S_IXUGO + | S_IWUSR | S_IWGRP, NULL, + NULL); + printk(KERN_INFO "debug: Initialization complete\n"); + initialized = 1; + } + up(&debug_lock); + + return rc; +} + +/* + * debug_register_view: + */ + +int debug_register_view(debug_info_t * id, struct debug_view *view) +{ + int rc = 0; + int i; + long flags; + mode_t mode = S_IFREG; + + if (!id) + goto out; + spin_lock_irqsave(&id->lock, flags); + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (id->views[i] == NULL) + break; + } + if (i == DEBUG_MAX_VIEWS) { + printk(KERN_WARNING "debug: cannot register view %s/%s\n", + id->name,view->name); + printk(KERN_WARNING + "debug: maximum number of views reached (%i)!\n", i); + rc = -1; + } + else { + id->views[i] = view; + if (view->prolog_proc || view->format_proc || view->header_proc) + mode |= S_IRUSR; + if (view->input_proc) + mode |= S_IWUSR; + id->proc_entries[i] = + debug_create_proc_dir_entry(id->proc_root_entry, + view->name, mode, + &debug_inode_ops, + &debug_file_ops); + rc = 0; + } + spin_unlock_irqrestore(&id->lock, flags); + out: + return rc; +} + +/* + * debug_unregister_view: + */ + +int debug_unregister_view(debug_info_t * id, struct debug_view *view) +{ + int rc = 0; + int i; + long flags; + + if (!id) + goto out; + spin_lock_irqsave(&id->lock, flags); + for (i = 0; i < DEBUG_MAX_VIEWS; i++) { + if (id->views[i] == view) + break; + } + if (i == DEBUG_MAX_VIEWS) + rc = -1; + else { + debug_delete_proc_dir_entry(id->proc_root_entry, + id->proc_entries[i]); + id->views[i] = NULL; + rc = 0; + } + spin_unlock_irqrestore(&id->lock, flags); + out: + return rc; +} + +/* + * functions for debug-views + *********************************** +*/ + +/* + * prints out actual debug level + */ + +static int debug_prolog_level_fn(debug_info_t * id, + struct debug_view *view, char *out_buf) +{ + int rc = 0; + + if (out_buf == NULL) { + rc = 2; + goto out; + } + if(id->level == -1) rc = sprintf(out_buf,"-\n"); + else rc = sprintf(out_buf, "%i\n", id->level); + out: + return rc; +} + +/* + * reads new debug level + */ + +static int debug_input_level_fn(debug_info_t * id, struct debug_view *view, + struct file *file, const char *user_buf, + size_t in_buf_size, loff_t * offset) +{ + char input_buf[1]; + int rc = in_buf_size; + + if (*offset != 0) + goto out; + if ((rc = copy_from_user(input_buf, user_buf, 1))) + goto out; + if (isdigit(input_buf[0])) { + int new_level = ((int) input_buf[0] - (int) '0'); + debug_set_level(id, new_level); + } else if(input_buf[0] == '-') { + debug_set_level(id, DEBUG_OFF_LEVEL); + } else { + printk(KERN_INFO "debug: level `%c` is not valid\n", + input_buf[0]); + } + out: + *offset += in_buf_size; + return rc; /* number of input characters */ +} + +/* + * prints debug header in raw format + */ + +int debug_raw_header_fn(debug_info_t * id, struct debug_view *view, + int area, debug_entry_t * entry, char *out_buf) +{ + int rc; + + rc = sizeof(debug_entry_t); + if (out_buf == NULL) + goto out; + memcpy(out_buf,entry,sizeof(debug_entry_t)); + out: + return rc; +} + +/* + * prints debug data in raw format + */ + +static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) +{ + int rc; + + rc = id->buf_size; + if (out_buf == NULL || in_buf == NULL) + goto out; + memcpy(out_buf, in_buf, id->buf_size); + out: + return rc; +} + +/* + * prints debug data in hex/ascii format + */ + +static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) +{ + int i, rc = 0; + + if (out_buf == NULL || in_buf == NULL) { + rc = id->buf_size * 4 + 3; + goto out; + } + for (i = 0; i < id->buf_size; i++) { + rc += sprintf(out_buf + rc, "%02x ", + ((unsigned char *) in_buf)[i]); + } + rc += sprintf(out_buf + rc, "| "); + for (i = 0; i < id->buf_size; i++) { + unsigned char c = in_buf[i]; + if (!isprint(c)) + rc += sprintf(out_buf + rc, "."); + else + rc += sprintf(out_buf + rc, "%c", c); + } + rc += sprintf(out_buf + rc, "\n"); + out: + return rc; +} + +/* + * prints header for debug entry + */ + +int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view, + int area, debug_entry_t * entry, char *out_buf) +{ + struct timeval time_val; + unsigned long long time; + char *except_str; + unsigned long caller; + int rc = 0; + + if (out_buf == NULL) { + rc = DEBUG_PROC_HEADER_SIZE; + goto out; + } + + time = entry->id.stck; + /* adjust todclock to 1970 */ + time -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); + tod_to_timeval(time, &time_val); + + if (entry->id.fields.exception) + except_str = "*"; + else + except_str = "-"; + caller = (unsigned long) entry->caller; +#if defined(CONFIG_ARCH_S390X) + rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %016lx ", + area, time_val.tv_sec, + time_val.tv_usec, except_str, + entry->id.fields.cpuid, caller); +#else + caller &= 0x7fffffff; + rc += sprintf(out_buf, "%02i %011lu:%06lu %1s %02i %08lx ", + area, time_val.tv_sec, + time_val.tv_usec, except_str, + entry->id.fields.cpuid, caller); +#endif + out: + return rc; +} + +/* + * 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: + */ + +void cleanup_module(void) +{ +#ifdef DEBUG + printk("debug_cleanup_module: \n"); +#endif + debug_delete_proc_dir_entry(&proc_root, debug_proc_root_entry); + return; +} + +#endif /* MODULE */ diff --git a/arch/s390/kernel/ebcdic.c b/arch/s390/kernel/ebcdic.c index 3c70c4aa5..fc7740649 100644 --- a/arch/s390/kernel/ebcdic.c +++ b/arch/s390/kernel/ebcdic.c @@ -161,7 +161,156 @@ __u8 _ebcasc[256] = /* - * EBCDIC 037 conversion table: + * ASCII (IBM PC 437) -> EBCDIC 500 + */ +__u8 _ascebc_500[256] = +{ + /*00 NUL SOH STX ETX EOT ENQ ACK BEL */ + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, + /*08 BS HT LF VT FF CR SO SI */ + /* ->NL */ + 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, + /*18 CAN EM SUB ESC FS GS RS US */ + /* ->IGS ->IRS ->IUS */ + 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, + /*20 SP ! " # $ % & ' */ + 0x40, 0x4F, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, + /*28 ( ) * + , - . / */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + /*30 0 1 2 3 4 5 6 7 */ + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + /*38 8 9 : ; < = > ? */ + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + /*40 @ A B C D E F G */ + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + /*48 H I J K L M N O */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + /*50 P Q R S T U V W */ + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + /*58 X Y Z [ \ ] ^ _ */ + 0xE7, 0xE8, 0xE9, 0x4A, 0xE0, 0x5A, 0x5F, 0x6D, + /*60 ` a b c d e f g */ + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + /*68 h i j k l m n o */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + /*70 p q r s t u v w */ + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + /*78 x y z { | } ~ DL */ + 0xA7, 0xA8, 0xA9, 0xC0, 0xBB, 0xD0, 0xA1, 0x07, + /*80*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*88*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*90*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*98*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*A0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*A8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*B0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*B8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*C0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*C8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*D0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*D8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*E0 sz */ + 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*E8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*F0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*F8*/ + 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF +}; + +/* + * EBCDIC 500 -> ASCII (IBM PC 437) + */ +__u8 _ebcasc_500[256] = +{ + /* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */ + 0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F, + /* 0x08 -GE -SPS -RPT VT FF CR SO SI */ + 0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + /* 0x10 DLE DC1 DC2 DC3 -RES -NL BS -POC + -ENP ->LF */ + 0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07, + /* 0x18 CAN EM -UBS -CU1 -IFS -IGS -IRS -ITB + -IUS */ + 0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + /* 0x20 -DS -SOS FS -WUS -BYP LF ETB ESC + -INP */ + 0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B, + /* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL + -SW */ + 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07, + /* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */ + 0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04, + /* 0x38 -SBS -IT -RFF -CU3 DC4 NAK ---- SUB */ + 0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A, + /* 0x40 SP RSP ä ---- */ + 0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86, + /* 0x48 [ . < ( + ! */ + 0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21, + /* 0x50 & ---- */ + 0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07, + /* 0x58 ß ] $ * ) ; ^ */ + 0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E, + /* 0x60 - / ---- Ä ---- ---- ---- */ + 0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F, + /* 0x68 ---- , % _ > ? */ + 0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F, + /* 0x70 ---- ---- ---- ---- ---- ---- ---- */ + 0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + /* 0x78 * ` : # @ ' = " */ + 0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22, + /* 0x80 * a b c d e f g */ + 0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + /* 0x88 h i ---- ---- ---- */ + 0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1, + /* 0x90 ° j k l m n o p */ + 0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, + /* 0x98 q r ---- ---- */ + 0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07, + /* 0xA0 ~ s t u v w x */ + 0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + /* 0xA8 y z ---- ---- ---- ---- */ + 0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07, + /* 0xB0 ---- § ---- */ + 0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC, + /* 0xB8 ---- | ---- ---- ---- ---- */ + 0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07, + /* 0xC0 { A B C D E F G */ + 0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + /* 0xC8 H I ---- ö ---- */ + 0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07, + /* 0xD0 } J K L M N O P */ + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + /* 0xD8 Q R ---- ü */ + 0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98, + /* 0xE0 \ S T U V W X */ + 0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + /* 0xE8 Y Z ---- Ö ---- ---- ---- */ + 0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07, + /* 0xF0 0 1 2 3 4 5 6 7 */ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + /* 0xF8 8 9 ---- ---- Ü ---- ---- ---- */ + 0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07 +}; + + +/* + * EBCDIC 037/500 conversion table: * from upper to lower case */ __u8 _ebc_tolower[256] = @@ -202,7 +351,7 @@ __u8 _ebc_tolower[256] = /* - * EBCDIC 037 conversion table: + * EBCDIC 037/500 conversion table: * from lower to upper case */ __u8 _ebc_toupper[256] = diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index e39e18623..a1125e933 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -81,6 +81,7 @@ state = 0 flags = 4 sigpending = 8 need_resched = 24 +tsk_ptrace = 28 processor = 60 /* PSW related defines */ @@ -88,6 +89,13 @@ disable = 0xFC enable = 0x03 daton = 0x04 +/* + * Base Address of this Module --- saved in __LC_ENTRY_BASE + */ + .globl entry_base +entry_base: + +#define BASED(name) name-entry_base(%r13) #if 0 /* some code left lying around in case we need a @@ -118,39 +126,37 @@ sysc_dn: */ #define SAVE_ALL(psworg) \ - st %r15,__LC_SAVE_AREA ; \ + stm %r13,%r15,__LC_SAVE_AREA ; \ + stam %a2,%a4,__LC_SAVE_AREA+12 ; \ + basr %r13,0 ; /* temp base pointer */ \ + l %r13,.Lentry_base-.(%r13) ; /* load &entry_base to %r13 */ \ tm psworg+1,0x01 ; /* test problem state bit */ \ - jz 0f ; /* skip stack setup save */ \ + bz BASED(.+12) ; /* skip stack setup save */ \ l %r15,__LC_KERNEL_STACK ; /* problem state -> load ksp */ \ -0: ahi %r15,-SP_SIZE ; /* make room for registers & psw */ \ - srl %r15,3 ; \ - sll %r15,3 ; /* align stack pointer to 8 */ \ - stm %r0,%r14,SP_R0(%r15) ; /* store gprs 0-14 to kernel stack */ \ + lam %a2,%a4,BASED(.Lc_ac) ; /* set ac.reg. 2 to primary space */ \ + /* and access reg. 4 to home space */ \ +0: s %r15,BASED(.Lc_spsize); /* make room for registers & psw */ \ + n %r15,BASED(.Lc0xfffffff8) ; /* align stack pointer to 8 */ \ + stm %r0,%r12,SP_R0(%r15) ; /* store gprs 0-12 to kernel stack */ \ st %r2,SP_ORIG_R2(%r15) ; /* store original content of gpr 2 */ \ - mvc SP_RF(4,%r15),__LC_SAVE_AREA ; /* move R15 to stack */ \ + mvc SP_RD(12,%r15),__LC_SAVE_AREA ; /* move R13-R15 to stack */ \ stam %a0,%a15,SP_AREGS(%r15) ; /* store access registers to kst. */ \ + mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 ; /* store ac. regs */ \ mvc SP_PSW(8,%r15),psworg ; /* move user PSW to stack */ \ - lhi %r0,psworg ; /* store trap indication */ \ + la %r0,psworg ; /* store trap indication */ \ st %r0,SP_TRAP(%r15) ; \ - xc 0(4,%r15),0(%r15) ; /* clear back chain */ \ - tm psworg+1,0x01 ; /* kmod.c .wishes the set_fs & gs */ \ - jz 1f ; /* to work across syscalls */ \ - slr %r0,%r0 ; \ - sar %a2,%r0 ; /* set ac.reg. 2 to primary space */ \ - lhi %r0,1 ; \ - sar %a4,%r0 ; /* set access reg. 4 to home space */ \ -1: + xc 0(4,%r15),0(%r15) ; /* clear back chain */ #define RESTORE_ALL \ - mvc __LC_RETURN_PSW(8,0),SP_PSW(%r15) ; /* move user PSW to lowcore */ \ - lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \ - lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ - ni __LC_RETURN_PSW+1(0),0xfd ; /* clear wait state bit */ \ - lpsw __LC_RETURN_PSW /* back to caller */ + mvc __LC_RETURN_PSW(8),SP_PSW(%r15) ; /* move user PSW to lowcore */ \ + lam %a0,%a15,SP_AREGS(%r15) ; /* load the access registers */ \ + lm %r0,%r15,SP_R0(%r15) ; /* load gprs 0-15 of user */ \ + ni __LC_RETURN_PSW+1,0xfd ; /* clear wait state bit */ \ + lpsw __LC_RETURN_PSW /* back to caller */ #define GET_CURRENT /* load pointer to task_struct to R9 */ \ - lhi %r9,-8192 ; \ - nr %r9,15 + lr %r9,%r15 ; \ + n %r9,BASED(.Lc0xffffe000) /* @@ -162,22 +168,24 @@ sysc_dn: */ .globl resume resume: + basr %r1,0 +resume_base: l %r4,_TSS_PTREGS(%r3) tm SP_PSW-SP_PTREGS(%r4),0x40 # is the new process using per ? - jz RES_DN1 # if not we're fine - stctl %r9,%r11,24(%r15) # We are using per stuff + bz resume_noper-resume_base(%r1) # if not we're fine + stctl %r9,%r11,24(%r15) # We are using per stuff clc _TSS_PER(12,%r3),24(%r15) - je RES_DN1 # we got away without bashing TLB's - lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't -RES_DN1: + be resume_noper-resume_base(%r1) # we got away w/o bashing TLB's + lctl %c9,%c11,_TSS_PER(%r3) # Nope we didn't +resume_noper: stm %r6,%r15,24(%r15) # store resume registers of prev task st %r15,_TSS_KSP(%r2) # store kernel stack ptr to prev->tss.ksp - lhi %r0,-8192 - nr %r0,%r15 + lr %r0,%r15 + n %r0,.Lc0xffffe000-resume_base(%r1) l %r15,_TSS_KSP(%r3) # load kernel stack ptr from next->tss.ksp - lhi %r1,8191 + l %r1,.Lc8191-resume_base(%r1) or %r1,%r15 - ahi %r1,1 + la %r1,1(%r1) st %r1,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack stam %a2,%a2,_TSS_AR2(%r2) # store kernel access reg. 2 stam %a4,%a4,_TSS_AR4(%r2) # store kernel access reg. 4 @@ -192,38 +200,19 @@ RES_DN1: * are executed with interrupts enabled. */ -sysc_lit: - sysc_do_signal: .long do_signal - sysc_do_softirq: .long do_softirq - sysc_schedule: .long schedule - sysc_trace: .long syscall_trace -#ifdef CONFIG_SMP - sysc_schedtail: .long schedule_tail -#endif - sysc_clone: .long sys_clone - sysc_fork: .long sys_fork - sysc_vfork: .long sys_vfork - sysc_sigreturn: .long sys_sigreturn - sysc_rt_sigreturn: .long sys_rt_sigreturn - sysc_execve: .long sys_execve - sysc_sigsuspend: .long sys_sigsuspend - sysc_rt_sigsuspend: .long sys_rt_sigsuspend - .globl system_call system_call: SAVE_ALL(0x20) - XC SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) + xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) pgm_system_call: - basr %r13,0 - ahi %r13,sysc_lit-. # setup base pointer R13 to sysc_lit slr %r8,%r8 # gpr 8 is call save (-> tracesys) ic %r8,0x8B # get svc number from lowcore stosm 24(%r15),0x03 # reenable interrupts GET_CURRENT # load pointer to task_struct to R9 sll %r8,2 - l %r8,sys_call_table-sysc_lit(8,%r13) # get address of system call - tm flags+3(%r9),0x20 # PF_TRACESYS - jnz sysc_tracesys + l %r8,sys_call_table-entry_base(8,%r13) # get address of system call + tm tsk_ptrace+3(%r9),0x02 # PT_TRACESYS + bnz BASED(sysc_tracesys) basr %r14,%r8 # call sys_xxxx st %r2,SP_R2(%r15) # store return value (change R2 on stack) # ATTENTION: check sys_execve_glue before @@ -232,24 +221,24 @@ pgm_system_call: sysc_return: GET_CURRENT # load pointer to task_struct to R9 tm SP_PSW+1(%r15),0x01 # returning to user ? - jno sysc_leave # no-> skip bottom half, resched & signal + bno BASED(sysc_leave) # no-> skip bottom half, resched & signal # # check, if bottom-half has to be done # l %r0,__LC_IRQ_STAT # get softirq_active n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask - jnz sysc_handle_bottom_half + bnz BASED(sysc_handle_bottom_half) # # check, if reschedule is needed # sysc_return_bh: icm %r0,15,need_resched(%r9) # get need_resched from task_struct - jnz sysc_reschedule + bnz BASED(sysc_reschedule) icm %r0,15,sigpending(%r9) # get sigpending from task_struct - jnz sysc_signal_return + bnz BASED(sysc_signal_return) sysc_leave: icm %r0,15,SP_SVC_STEP(%r15) # get sigpending from task_struct - jnz pgm_svcret + bnz BASED(pgm_svcret) stnsm 24(%r15),disable # disable I/O and ext. interrupts RESTORE_ALL @@ -259,24 +248,24 @@ sysc_leave: sysc_signal_return: la %r2,SP_PTREGS(%r15) # load pt_regs sr %r3,%r3 # clear *oldset - l %r1,sysc_do_signal-sysc_lit(%r13) - la %r14,sysc_leave-sysc_lit(%r13) + l %r1,BASED(.Ldo_signal) + la %r14,BASED(sysc_leave) br %r1 # return point is sysc_leave # # call trace before and after sys_call # sysc_tracesys: - l %r1,sysc_trace-sysc_lit(%r13) - lhi %r2,-ENOSYS + l %r1,BASED(.Ltrace) + l %r2,BASED(.Lc_ENOSYS) st %r2,SP_R2(%r15) # give sysc_trace an -ENOSYS retval basr %r14,%r1 lm %r3,%r6,SP_R3(%r15) l %r2,SP_ORIG_R2(%r15) basr %r14,%r8 # call sys_xxx st %r2,SP_R2(%r15) # store return value - l %r1,sysc_trace-sysc_lit(%r13) - la %r14,sysc_return-sysc_lit(%r13) + l %r1,BASED(.Ltrace) + la %r14,BASED(sysc_return) br %r1 # return point is sysc_return @@ -285,16 +274,16 @@ sysc_tracesys: # is zero # sysc_handle_bottom_half: - l %r1,sysc_do_softirq-sysc_lit(%r13) - la %r14,sysc_return_bh-sysc_lit(%r13) + l %r1,BASED(.Ldo_softirq) + la %r14,BASED(sysc_return_bh) br %r1 # call do_softirq # # call schedule with sysc_return as return-address # sysc_reschedule: - l %r1,sysc_schedule-sysc_lit(%r13) - la %r14,sysc_return-sysc_lit(%r13) + l %r1,BASED(.Lschedule) + la %r14,BASED(sysc_return) br %r1 # call scheduler, return to sysc_return # @@ -303,17 +292,17 @@ sysc_reschedule: .globl ret_from_fork ret_from_fork: basr %r13,0 - ahi %r13,sysc_lit-. # setup base pointer R13 to $SYSCDAT + l %r13,.Lentry_base-.(%r13) # setup base pointer to &entry_base GET_CURRENT # load pointer to task_struct to R9 stosm 24(%r15),0x03 # reenable interrupts sr %r0,%r0 # child returns 0 st %r0,SP_R2(%r15) # store return value (change R2 on stack) #ifdef CONFIG_SMP - l %r1,sysc_schedtail-sysc_lit(%r13) - la %r14,sysc_return-sysc_lit(%r13) + l %r1,BASED(.Lschedtail) + la %r14,BASED(sysc_return) br %r1 # call schedule_tail, return to sysc_return #else - j sysc_return + b BASED(sysc_return) #endif # @@ -324,22 +313,22 @@ ret_from_fork: # sys_clone_glue: la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,sysc_clone-sysc_lit(%r13) + l %r1,BASED(.Lclone) br %r1 # branch to sys_clone sys_fork_glue: la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,sysc_fork-sysc_lit(%r13) + l %r1,BASED(.Lfork) br %r1 # branch to sys_fork sys_vfork_glue: la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,sysc_vfork-sysc_lit(%r13) + l %r1,BASED(.Lvfork) br %r1 # branch to sys_vfork sys_execve_glue: la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,sysc_execve-sysc_lit(%r13) + l %r1,BASED(.Lexecve) lr %r12,%r14 # save return address basr %r14,%r1 # call sys_execve ltr %r2,%r2 # check if execve failed @@ -349,12 +338,12 @@ sys_execve_glue: sys_sigreturn_glue: la %r2,SP_PTREGS(%r15) # load pt_regs as parameter - l %r1,sysc_sigreturn-sysc_lit(%r13) + l %r1,BASED(.Lsigreturn) br %r1 # branch to sys_sigreturn sys_rt_sigreturn_glue: la %r2,SP_PTREGS(%r15) # load pt_regs as parameter - l %r1,sysc_rt_sigreturn-sysc_lit(%r13) + l %r1,BASED(.Lrt_sigreturn) br %r1 # branch to sys_sigreturn # @@ -369,7 +358,7 @@ sys_sigsuspend_glue: lr %r4,%r3 # move history1 parameter lr %r3,%r2 # move history0 parameter la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter - l %r1,sysc_sigsuspend-sysc_lit(%r13) + l %r1,BASED(.Lsigsuspend) la %r14,4(%r14) # skip store of return value br %r1 # branch to sys_sigsuspend @@ -377,10 +366,15 @@ sys_rt_sigsuspend_glue: lr %r4,%r3 # move sigsetsize parameter lr %r3,%r2 # move unewset parameter la %r2,SP_PTREGS(%r15) # load pt_regs as first parameter - l %r1,sysc_rt_sigsuspend-sysc_lit(%r13) + l %r1,BASED(.Lrt_sigsuspend) la %r14,4(%r14) # skip store of return value br %r1 # branch to sys_rt_sigsuspend +sys_sigaltstack_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + l %r1,BASED(.Lsigaltstack) + br %r1 # branch to sys_sigreturn + .globl sys_call_table sys_call_table: .long sys_ni_syscall /* 0 */ @@ -459,7 +453,7 @@ sys_call_table: .long sys_sigpending .long sys_sethostname .long sys_setrlimit /* 75 */ - .long sys_getrlimit + .long sys_old_getrlimit .long sys_getrusage .long sys_gettimeofday .long sys_settimeofday @@ -569,13 +563,13 @@ sys_call_table: .long sys_getcwd .long sys_capget .long sys_capset /* 185 */ - .long sys_sigaltstack + .long sys_sigaltstack_glue .long sys_sendfile .long sys_ni_syscall /* streams1 */ .long sys_ni_syscall /* streams2 */ .long sys_vfork_glue /* 190 */ .long sys_getrlimit - .long sys_ni_syscall /* FIXME: problem with sys_mmap2: 6 parms */ + .long sys_mmap2 .long sys_truncate64 .long sys_ftruncate64 .long sys_stat64 /* 195 */ @@ -604,7 +598,8 @@ sys_call_table: .long sys_mincore .long sys_madvise .long sys_getdents64 /* 220 */ - .rept 255-220 + .long sys_fcntl64 + .rept 255-221 .long sys_ni_syscall .endr @@ -612,13 +607,6 @@ sys_call_table: * Program check handler routine */ -pgm_lit: - pgm_handle_per: .long handle_per_exception - pgm_jump_table: .long pgm_check_table - pgm_sysc_ret: .long sysc_return - pgm_sysc_lit: .long sysc_lit - pgm_do_signal: .long do_signal - .globl pgm_check_handler pgm_check_handler: /* @@ -634,110 +622,131 @@ pgm_check_handler: * we just ignore the PER event (FIXME: is there anything we have to do * for LPSW?). */ + stm %r13,%r15,__LC_SAVE_AREA + stam %a2,%a4,__LC_SAVE_AREA+12 + basr %r13,0 # temp base pointer + l %r13,.Lentry_base-.(%r13)# load &entry_base to %r13 tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception - jz pgm_sv # skip if not + bz BASED(pgm_sv) # skip if not tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on - jnz pgm_sv # skip if it is + bnz BASED(pgm_sv) # skip if it is # ok its one of the special cases, now we need to find out which one clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW - je pgm_svcper + be BASED(pgm_svcper) # no interesting special case, ignore PER event - lpsw 0x28 + lm %r13,%r15,__LC_SAVE_AREA + lpsw 0x28 # it was a single stepped SVC that is causing all the trouble pgm_svcper: - SAVE_ALL(0x20) + tm 0x21,0x01 # test problem state bit + bz BASED(.+12) # skip stack & access regs setup + l %r15,__LC_KERNEL_STACK # problem state -> load ksp + lam %a2,%a4,BASED(.Lc_ac) # set ac.reg. 2 to primary space + # and access reg. 4 to home space + s %r15,BASED(.Lc_spsize) # make room for registers & psw + n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8 + stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack + st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 + mvc SP_RD(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack + stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. + mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs + mvc SP_PSW(8,%r15),0x20 # move user PSW to stack + la %r0,0x20 # store trap indication + st %r0,SP_TRAP(%r15) + xc 0(4,%r15),0(%r15) # clear back chain mvi SP_SVC_STEP(%r15),1 # make SP_SVC_STEP nonzero mvc SP_PGM_OLD_ILC(4,%r15),__LC_PGM_ILC # save program check information - j pgm_system_call # now do the svc + b BASED(pgm_system_call) # now do the svc pgm_svcret: - lh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack - lhi %r0,0x28 - st %r0,SP_TRAP(%r15) # set new trap indicator + mvi SP_TRAP+3(%r15),0x28 # set trap indication back to pgm_chk + lh %r7,SP_PGM_OLD_ILC(%r15) # get ilc from stack xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) - basr %r13,0 - ahi %r13,pgm_lit-. # setup base pointer - j pgm_no_sv + b BASED(pgm_no_sv) pgm_sv: - SAVE_ALL(0x28) - XC SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) - basr %r13,0 - ahi %r13,pgm_lit-. # setup base pointer R13 to $PGMDAT + tm 0x29,0x01 # test problem state bit + bz BASED(.+12) # skip stack & access regs setup + l %r15,__LC_KERNEL_STACK # problem state -> load ksp + lam %a2,%a4,BASED(.Lc_ac) # set ac.reg. 2 to primary space + # and access reg. 4 to home space + s %r15,BASED(.Lc_spsize) # make room for registers & psw + n %r15,BASED(.Lc0xfffffff8) # align stack pointer to 8 + stm %r0,%r12,SP_R0(%r15) # store gprs 0-12 to kernel stack + st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 + mvc SP_RD(12,%r15),__LC_SAVE_AREA # move R13-R15 to stack + stam %a0,%a15,SP_AREGS(%r15) # store access registers to kst. + mvc SP_AREGS+8(12,%r15),__LC_SAVE_AREA+12 # store ac. regs + mvc SP_PSW(8,%r15),0x28 # move user PSW to stack + la %r0,0x28 # store trap indication + st %r0,SP_TRAP(%r15) + xc 0(4,%r15),0(%r15) # clear back chain + xc SP_SVC_STEP(4,%r15),SP_SVC_STEP(%r15) lh %r7,__LC_PGM_ILC # load instruction length pgm_no_sv: lh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it stosm 24(%r15),0x03 # reenable interrupts lr %r3,%r8 - lhi %r0,0x7f + la %r0,0x7f nr %r3,%r0 # clear per-event-bit - je pgm_dn # none of Martins exceptions occured bypass - l %r9,pgm_jump_table-pgm_lit(%r13) + be BASED(pgm_dn) # none of Martins exceptions occured bypass + l %r9,BASED(.Ljump_table) sll %r3,2 l %r9,0(%r3,%r9) # load address of handler routine la %r2,SP_PTREGS(%r15) # address of register-save area srl %r3,2 - chi %r3,0x4 # protection-exception ? - jne pgm_go # if not, + cl %r3,BASED(.Lc4) # protection-exception ? + bne BASED(pgm_go) # if not, l %r5,SP_PSW+4(15) # load psw addr sr %r5,%r7 # substract ilc from psw st %r5,SP_PSW+4(15) # store corrected psw addr pgm_go: basr %r14,%r9 # branch to interrupt-handler -pgm_dn: lhi %r0,0x80 +pgm_dn: la %r0,0x80 nr %r8,%r0 # check for per exception - je pgm_return + be BASED(pgm_return) la %r2,SP_PTREGS(15) # address of register-save area - l %r9,pgm_handle_per-pgm_lit(%r13) # load adr. of per handler - l %r14,pgm_sysc_ret-pgm_lit(%r13) # load adr. of system return - l %r13,pgm_sysc_lit-pgm_lit(%r13) + l %r9,BASED(.Lhandle_per) # load adr. of per handler + la %r14,BASED(sysc_return) # load adr. of system return br %r9 # branch to handle_per_exception + # # the backend code is the same as for sys-call # pgm_return: - l %r14,pgm_sysc_ret-pgm_lit(%r13) - l %r13,pgm_sysc_lit-pgm_lit(%r13) - br %r14 + b BASED(sysc_return) /* * IO interrupt handler routine */ -io_lit: - io_do_IRQ: .long do_IRQ - io_schedule: .long schedule - io_do_signal: .long do_signal - io_do_softirq: .long do_softirq - .globl io_int_handler io_int_handler: SAVE_ALL(0x38) - basr %r13,0 - ahi %r13,io_lit-. # setup base pointer R13 to $IODAT la %r2,SP_PTREGS(%r15) # address of register-save area sr %r3,%r3 icm %r3,%r3,__LC_SUBCHANNEL_NR # load subchannel nr & extend to int - l %r4,__LC_IO_INT_PARM # load interuption parm - l %r9,io_do_IRQ-io_lit(%r13) # load address of do_IRQ + l %r4,__LC_IO_INT_PARM # load interruption parm + l %r5,__LC_IO_INT_WORD # load interruption word + l %r9,BASED(.Ldo_IRQ) # load address of do_IRQ basr %r14,%r9 # branch to standard irq handler io_return: GET_CURRENT # load pointer to task_struct to R9 tm SP_PSW+1(%r15),0x01 # returning to user ? - jz io_leave # no-> skip resched & signal + bz BASED(io_leave) # no-> skip resched & signal stosm 24(%r15),0x03 # reenable interrupts # # check, if bottom-half has to be done # l %r0,__LC_IRQ_STAT # get softirq_active n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask - jnz io_handle_bottom_half + bnz BASED(io_handle_bottom_half) io_return_bh: # # check, if reschedule is needed # icm %r0,15,need_resched(%r9) # get need_resched from task_struct - jnz io_reschedule + bnz BASED(io_reschedule) icm %r0,15,sigpending(%r9) # get sigpending from task_struct - jnz io_signal_return + bnz BASED(io_signal_return) io_leave: stnsm 24(%r15),disable # disable I/O and ext. interrupts RESTORE_ALL @@ -747,16 +756,16 @@ io_leave: # is zero # io_handle_bottom_half: - l %r1,io_do_softirq-io_lit(%r13) - la %r14,io_return_bh-io_lit(%r13) + l %r1,BASED(.Ldo_softirq) + la %r14,BASED(io_return_bh) br %r1 # call do_softirq # # call schedule with io_return as return-address # io_reschedule: - l %r1,io_schedule-io_lit(%r13) - la %r14,io_return-io_lit(%r13) + l %r1,BASED(.Lschedule) + la %r14,BASED(io_return) br %r1 # call scheduler, return to io_return # @@ -765,103 +774,46 @@ io_reschedule: io_signal_return: la %r2,SP_PTREGS(%r15) # load pt_regs sr %r3,%r3 # clear *oldset - l %r1,io_do_signal-io_lit(%r13) - la %r14,io_leave-io_lit(%r13) + l %r1,BASED(.Ldo_signal) + la %r14,BASED(io_leave) br %r1 # return point is io_leave /* * External interrupt handler routine */ -ext_lit: - ext_timer_int: .long do_timer_interrupt -#ifdef CONFIG_SMP - ext_call_int: .long do_ext_call_interrupt -#endif -#ifdef CONFIG_HWC - ext_hwc_int: .long do_hwc_interrupt -#endif -#ifdef CONFIG_MDISK - ext_mdisk_int: .long do_mdisk_interrupt -#endif -#ifdef CONFIG_IUCV - ext_iucv_int: .long do_iucv_interrupt -#endif - ext_io_lit: .long io_lit - ext_io_return: .long io_return - .globl ext_int_handler ext_int_handler: SAVE_ALL(0x18) - basr %r13,0 - ahi %r13,ext_lit-. # setup base pointer R13 to $EXTDAT la %r2,SP_PTREGS(%r15) # address of register-save area lh %r3,__LC_EXT_INT_CODE # error code -#ifdef CONFIG_SMP - chi %r3,0x1202 # EXTERNAL_CALL - jne ext_no_extcall - l %r9,ext_call_int-ext_lit(%r13) # load ext_call_interrupt - l %r14,ext_io_return-ext_lit(%r13) - l %r13,ext_io_lit-ext_lit(%r13) - br %r9 # branch to ext call handler -ext_no_extcall: -#endif - chi %r3,0x1004 # CPU_TIMER - jne ext_no_timer - l %r9,ext_timer_int-ext_lit(%r13) # load timer_interrupt - l %r14,ext_io_return-ext_lit(%r13) - l %r13,ext_io_lit-ext_lit(%r13) - br %r9 # branch to ext call handler -ext_no_timer: -#ifdef CONFIG_HWC - chi %r3,0x2401 # HWC interrupt - jne ext_no_hwc - l %r9,ext_hwc_int-ext_lit(%r13) # load addr. of hwc routine - l %r14,ext_io_return-ext_lit(%r13) - l %r13,ext_io_lit-ext_lit(%r13) - br %r9 # branch to ext call handler -ext_no_hwc: -#endif -#ifdef CONFIG_MDISK - chi %r3,0x2603 # diag 250 (VM) interrupt - jne ext_no_mdisk - l %r9,ext_mdisk_int-ext_lit(%r13) - l %r14,ext_io_return-ext_lit(%r13) - l %r13,ext_io_lit-ext_lit(%r13) - br %r9 # branch to ext call handler -ext_no_mdisk: -#endif -#ifdef CONFIG_IUCV - chi %r3,0x4000 # diag 250 (VM) interrupt - jne ext_no_iucv - l %r9,ext_iucv_int-ext_lit(%r13) - l %r14,ext_io_return-ext_lit(%r13) - l %r13,ext_io_lit-ext_lit(%r13) - br %r9 # branch to ext call handler -ext_no_iucv: -#endif - - l %r14,ext_io_return-ext_lit(%r13) - l %r13,ext_io_lit-ext_lit(%r13) - br %r14 # use backend code of io_int_handler + lr %r1,%r3 # calculate index = code & 0xff + n %r1,BASED(.Lc0xff) + sll %r1,2 + l %r9,BASED(.Lext_hash) + l %r9,0(%r1,%r9) # get first list entry for hash value + ltr %r9,%r9 # == NULL ? + bz BASED(io_return) # yes, nothing to do, exit +ext_int_loop: + ch %r3,8(%r9) # compare external interrupt code + be BASED(ext_int_found) + icm %r9,15,0(%r9) # next list entry + bnz BASED(ext_int_loop) + b BASED(io_return) +ext_int_found: + l %r9,4(%r9) # get handler address + la %r14,BASED(io_return) + br %r9 # branch to ext call handler /* * Machine check handler routines */ -mcck_lit: - mcck_crw_pending: .long do_crw_pending - .globl mcck_int_handler mcck_int_handler: SAVE_ALL(0x30) - basr %r13,0 - ahi %r13,mcck_lit-. # setup base pointer R13 to $MCCKDAT - tm __LC_MCCK_CODE+1,0x40 - jno mcck_no_crw - l %r1,mcck_crw_pending-mcck_lit(%r13) - basr %r14,%r1 # call do_crw_pending -mcck_no_crw: + l %r1,BASED(.Ls390_mcck) + basr %r14,%r1 # call machine check handler mcck_return: RESTORE_ALL @@ -876,11 +828,11 @@ restart_int_handler: lam %a0,%a15,__LC_AREGS_SAVE_AREA stosm 0(%r15),daton # now we can turn dat on lm %r6,%r15,24(%r15) # load registers from clone - bras %r14,restart_go - .long start_secondary -restart_go: - l %r14,0(%r14) + basr %r14,0 + l %r14,restart_addr-.(%r14) br %r14 # branch to start_secondary +restart_addr: + .long start_secondary #else /* * If we do not run with SMP enabled, let the new CPU crash ... @@ -896,3 +848,48 @@ restart_crash: restart_go: #endif +/* + * Integer constants + */ + .align 4 +.Lc0xfffffff8: .long -8 # to align stack pointer to 8 +.Lc0xffffe000: .long -8192 # to round stack pointer to &task_struct +.Lc8191: .long 8191 +.Lc_spsize: .long SP_SIZE +.Lc_ac: .long 0,0,1 +.Lc_ENOSYS: .long -ENOSYS +.Lc4: .long 4 +.Lc0x1202: .long 0x1202 +.Lc0x1004: .long 0x1004 +.Lc0x2401: .long 0x2401 +.Lc0x4000: .long 0x4000 +.Lc0xff: .long 0xff + +/* + * Symbol constants + */ +.Ls390_mcck: .long s390_do_machine_check +.Ldo_IRQ: .long do_IRQ +.Ldo_signal: .long do_signal +.Ldo_softirq: .long do_softirq +.Lentry_base: .long entry_base +.Lext_hash: .long ext_int_hash +.Lhandle_per: .long handle_per_exception +.Ljump_table: .long pgm_check_table +.Lschedule: .long schedule +.Lclone: .long sys_clone +.Lexecve: .long sys_execve +.Lfork: .long sys_fork +.Lrt_sigreturn:.long sys_rt_sigreturn +.Lrt_sigsuspend: + .long sys_rt_sigsuspend +.Lsigreturn: .long sys_sigreturn +.Lsigsuspend: .long sys_sigsuspend +.Lsigaltstack: .long sys_sigaltstack +.Ltrace: .long syscall_trace +.Lvfork: .long sys_vfork + +#ifdef CONFIG_SMP +.Lschedtail: .long schedule_tail +#endif + diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index a3b5df25c..d41f398d8 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -2,20 +2,29 @@ * arch/s390/kernel/head.S * * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Hartmut Penner (hp@de.ibm.com), * Martin Schwidefsky (schwidefsky@de.ibm.com), + * Rob van der Heij (rvdhei@iae.nl) * - * There are 4 different IPL methods + * There are 5 different IPL methods * 1) load the image directly into ram at address 0 and do an PSW restart * 2) linload will load the image from address 0x10000 to memory 0x10000 * and start the code thru LPSW 0x0008000080010000 (VM only, deprecated) * 3) generate the tape ipl header, store the generated image on a tape * and ipl from it + * In case of SL tape you need to IPL 5 times to get past VOL1 etc * 4) generate the vm reader ipl header, move the generated image to the * VM reader (use option NOH!) and do a ipl from reader (VM only) + * 5) direct call of start by the SALIPL loader * We use the cpuid to distinguish between VM and native ipl * params for kernel are pushed to 0x10400 (see setup.h) + + Changes: + Okt 25 2000 <rvdheij@iae.nl> + added code to skip HDR and EOF to allow SL tape IPL (5 retries) + changed first CCW from rewind to backspace block + */ #include <linux/config.h> @@ -24,40 +33,13 @@ #ifndef CONFIG_IPL .org 0 - .long 0x00080000,0x80000000+iplstart # Just a restart PSW - -iplstart: - l %r12,.Lparm # pointer to parameter area -# -# find out memory size -# - mvc 104(8,0),.Lpcmem0 # setup program check handler - slr %r2,%r2 - lhi %r3,1 - sll %r3,20 -.Lloop0: - l %r0,0(%r2) # test page - ar %r2,%r3 # add 1M - jnm .Lloop0 # r1 < 0x80000000 -> loop -.Lchkmem0: - n %r2,.L4malign0 # align to multiples of 4M - st %r2,MEMORY_SIZE-PARMAREA(%r12) # store memory size - slr %r2,%r2 - st %r2,INITRD_SIZE-PARMAREA(%r12) # null ramdisk - st %r2,INITRD_START-PARMAREA(%r12) - j start - -.Lparm: .long PARMAREA -.L4malign0:.long 0xffc00000 - .align 8 -.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0 - + .long 0x00080000,0x80000000+startup # Just a restart PSW #else #ifdef CONFIG_IPL_TAPE #define IPL_BS 1024 .org 0 .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded - .long 0x07000000,0x60000001 # by ipl to addresses 0-23. + .long 0x27000000,0x60000001 # by ipl to addresses 0-23. .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs). .long 0x00000000,0x00000000 # external old psw .long 0x00000000,0x00000000 # svc old psw @@ -74,92 +56,6 @@ iplstart: .long 0x00080000,0x80000000+.Lioint # io new psw .org 0x100 -iplstart: - l %r1,0xb8 # load ipl subchannel number - lhi %r2,IPL_BS # load start address - bras %r14,.Lloader # load rest of ipl image - st %r1,__LC_IPLDEV # store ipl device number - l %r12,.Lparm # pointer to parameter area - -# -# find out memory size -# - mvc 104(8,0),.Lpcmem0 # setup program check handler - slr %r2,%r2 - lhi %r3,1 - sll %r3,20 -.Lloop0: - l %r0,0(%r2) # test page - ar %r2,%r3 # add 1M - jnm .Lloop0 # r1 < 0x80000000 -> loop -.Lchkmem0: - n %r2,.L4malign0 # align to multiples of 4M - st %r2,MEMORY_SIZE-PARMAREA(%r12) # store memory size - c %r2,.Lbigmem # more than 64 MB of memory ? - jl .Lmemok # if yes load ramdisk to 32 MB - mvc INITRD_START-PARMAREA(4,%r12),.Lrdstart -.Lmemok: - -# -# load parameter file from tape -# - l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp - bras %r14,.Lloader # load parameter file - ltr %r2,%r2 # got anything ? - jz .Lnopf - chi %r2,895 - jnh .Lnotrunc - lhi %r2,895 -.Lnotrunc: - l %r4,INITRD_START-PARMAREA(%r12) - la %r5,0(%r4,%r2) - lr %r3,%r2 -.Lidebc: - tm 0(%r5),0x80 # high order bit set ? - jo .Ldocv # yes -> convert from EBCDIC - ahi %r5,-1 - brct %r3,.Lidebc - j .Lnocv -.Ldocv: - l %r3,.Lcvtab - tr 0(256,%r4),0(%r3) # convert parameters to ascii - tr 256(256,%r4),0(%r3) - tr 512(256,%r4),0(%r3) - tr 768(122,%r4),0(%r3) -.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line - mvc 0(256,%r3),0(%r4) - mvc 256(256,%r3),256(%r4) - mvc 512(256,%r3),512(%r4) - mvc 768(122,%r3),768(%r4) - slr %r0,%r0 - j .Lcntlp -.Ldelspc: - ic %r0,0(%r2,%r3) - chi %r0,0x20 # is it a space ? - je .Lcntlp - ahi %r2,1 - j .Leolp -.Lcntlp: - brct %r2,.Ldelspc -.Leolp: - slr %r0,%r0 - stc %r0,0(%r2,%r3) # terminate buffer -.Lnopf: - -# -# load ramdisk from tape -# - l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk - bras %r14,.Lloader # load ramdisk - st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk - ltr %r2,%r2 - jnz .Lrdcont - st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it -.Lrdcont: -# -# everything loaded, go for it -# - j start # # subroutine for loading from tape # Paramters: @@ -173,32 +69,32 @@ iplstart: lctl %c6,%c6,.Lcr6 slr %r2,%r2 .Lldlp: - lhi %r6,3 # 3 retries + la %r6,3 # 3 retries .Lssch: ssch 0(%r3) # load chunk of IPL_BS bytes - jnz .Llderr + bnz .Llderr .Lw4end: - bras %r14,.Lwait4io + bas %r14,.Lwait4io tm 8(%r5),0x82 # do we have a problem ? - jnz .Lrecov + bnz .Lrecov slr %r7,%r7 icm %r7,3,10(%r5) # get residual count lcr %r7,%r7 - ahi %r7,IPL_BS # IPL_BS-residual=#bytes read + la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read ar %r2,%r7 # add to total size tm 8(%r5),0x01 # found a tape mark ? - jnz .Ldone + bnz .Ldone l %r0,.Lccwread+4 # update CCW data addresses ar %r0,%r7 st %r0,.Lccwread+4 - j .Lldlp + b .Lldlp .Ldone: l %r14,.Lldret br %r14 # r2 contains the total size .Lrecov: - bras %r14,.Lsense # do the sensing - brct %r6,.Lssch # dec. retry count & branch - j .Llderr + bas %r14,.Lsense # do the sensing + bct %r6,.Lssch # dec. retry count & branch + b .Llderr # # Sense subroutine # @@ -206,11 +102,11 @@ iplstart: st %r14,.Lsnsret la %r7,.Lorbsense ssch 0(%r7) # start sense command - jnz .Llderr - bras %r14,.Lwait4io + bnz .Llderr + bas %r14,.Lwait4io l %r14,.Lsnsret tm 8(%r5),0x82 # do we have a problem ? - jnz .Llderr + bnz .Llderr br %r14 # # Wait for interrupt subroutine @@ -219,13 +115,13 @@ iplstart: lpsw .Lwaitpsw .Lioint: c %r1,0xb8 # compare subchannel number - jne .Lwait4io + bne .Lwait4io tsch 0(%r5) slr %r0,%r0 tm 8(%r5),0x82 # do we have a problem ? - jnz .Lwtexit + bnz .Lwtexit tm 8(%r5),0x04 # got device end ? - jz .Lwait4io + bz .Lwait4io .Lwtexit: br %r14 .Llderr: @@ -249,18 +145,12 @@ iplstart: .Lcr6: .long 0xff000000 .align 8 .Lcrash:.long 0x000a0000,0x00000000 -.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0 -.Lparm: .long PARMAREA -.L4malign0:.long 0xffc00000 -.Lbigmem:.long 0x04000000 -.Lrdstart:.long 0x02000000 .Lldret:.long 0 .Lsnsret: .long 0 -.Lcvtab:.long _ebcasc # ebcdic to ascii table - #endif /* CONFIG_IPL_TAPE */ #ifdef CONFIG_IPL_VM +#define IPL_BS 0x730 .org 0 .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded .long 0x02000018,0x60000050 # by ipl to addresses 0-23. @@ -287,103 +177,7 @@ iplstart: .long 0x02000690,0x60000050 .long 0x020006e0,0x20000050 - .org 0xf0 -iplstart: - l %r1,0xb8 # load ipl subchannel number - lhi %r2,0x730 # load start address - bras %r14,.Lloader # load rest of ipl image - st %r1,__LC_IPLDEV # store ipl device number - l %r12,.Lparm # pointer to parameter area - -# -# find out memory size -# - mvc 104(8,0),.Lpcmem0 # setup program check handler - slr %r2,%r2 - lhi %r3,1 - sll %r3,20 -.Lloop0: - l %r0,0(%r2) # test page - ar %r2,%r3 # add 1M - jnm .Lloop0 # r1 < 0x80000000 -> loop -.Lchkmem0: - n %r2,.L4malign0 # align to multiples of 4M - st %r2,MEMORY_SIZE-PARMAREA(%r12) # store memory size - c %r2,.Lbigmem # more than 64 MB of memory ? - jl .Lmemok # if yes load ramdisk to 32 MB - mvc INITRD_START-PARMAREA(4,%r12),.Lrdstart -.Lmemok: - -# -# load parameter file from reader -# - l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp - bras %r14,.Lloader # load parameter file - ltr %r2,%r2 # got anything ? - jz .Lnopf - chi %r2,895 - jnh .Lnotrunc - lhi %r2,895 -.Lnotrunc: - l %r4,INITRD_START-PARMAREA(%r12) - la %r5,0(%r4,%r2) - lr %r3,%r2 -.Lidebc: - tm 0(%r5),0x80 # high order bit set ? - jo .Ldocv # yes -> convert from EBCDIC - ahi %r5,-1 - brct %r3,.Lidebc - j .Lnocv -.Ldocv: - l %r3,.Lcvtab - tr 0(256,%r4),0(%r3) # convert parameters to ascii - tr 256(256,%r4),0(%r3) - tr 512(256,%r4),0(%r3) - tr 768(122,%r4),0(%r3) -.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line - mvc 0(256,%r3),0(%r4) - mvc 256(256,%r3),256(%r4) - mvc 512(256,%r3),512(%r4) - mvc 768(122,%r3),768(%r4) - slr %r0,%r0 - j .Lcntlp -.Ldelspc: - ic %r0,0(%r2,%r3) - chi %r0,0x20 # is it a space ? - je .Lcntlp - ahi %r2,1 - j .Leolp -.Lcntlp: - brct %r2,.Ldelspc -.Leolp: - slr %r0,%r0 - stc %r0,0(%r2,%r3) # terminate buffer -.Lnopf: - -# -# load ramdisk from reader -# - l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk - bras %r14,.Lloader # load ramdisk - st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk - ltr %r2,%r2 - jnz .Lrdcont - st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it -.Lrdcont: - -# -# everything loaded, reset files in reader, then go for it -# - stidp __LC_CPUID # store cpuid - lh %r0,__LC_CPUID+4 # get cpu version - chi %r0,0x7490 # running on P/390 ? - je start # no -> skip reset - la %r2,.Lreset - lhi %r3,26 - .long 0x83230008 - j start - # # subroutine for loading cards from the reader # @@ -394,29 +188,29 @@ iplstart: la %r7,20 .Linit: st %r2,4(%r6) # initialize CCW data addresses - ahi %r2,0x50 - ahi %r6,8 - brct 7,.Linit + la %r2,0x50(%r2) + la %r6,8(%r6) + bct 7,.Linit lctl %c6,%c6,.Lcr6 # set IO subclass mask slr %r2,%r2 .Lldlp: ssch 0(%r3) # load chunk of 1600 bytes - jnz .Llderr + bnz .Llderr .Lwait4irq: mvc __LC_IO_NEW_PSW(8),.Lnewpsw # set up IO interrupt psw lpsw .Lwaitpsw .Lioint: c %r1,0xb8 # compare subchannel number - jne .Lwait4irq + bne .Lwait4irq tsch 0(%r5) slr %r0,%r0 ic %r0,8(%r5) # get device status chi %r0,8 # channel end ? - je .Lcont + be .Lcont chi %r0,12 # channel end + device end ? - je .Lcont + be .Lcont l %r0,4(%r5) s %r0,8(%r3) # r0/8 = number of ccws executed @@ -436,9 +230,9 @@ iplstart: ahi %r0,0x640 st %r0,4(%r6) ahi %r6,8 - brct 7,.Lincr + bct 7,.Lincr - j .Lldlp + b .Lldlp .Llderr: lpsw .Lcrash @@ -447,16 +241,7 @@ iplstart: .Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 .Lcr6: .long 0xff000000 .Lloadp:.long 0,0 -.Lparm: .long PARMAREA -.L4malign0:.long 0xffc00000 -.Lbigmem:.long 0x04000000 -.Lrdstart:.long 0x02000000 -.Lcvtab:.long _ebcasc # ebcdic to ascii table -.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40 - .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6 - .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold" .align 8 -.Lpcmem0:.long 0x00080000,0x80000000 + .Lchkmem0 .Lcrash:.long 0x000a0000,0x00000000 .Lnewpsw: .long 0x00080000,0x80000000+.Lioint @@ -468,79 +253,330 @@ iplstart: .long 0x02600050,0x00000000 .endr .long 0x02200050,0x00000000 - - .org 0x730 # end of the area loaded by the ipl channel program #endif /* CONFIG_IPL_VM */ +iplstart: + lh %r1,0xb8 # test if subchannel number + bct %r1,.Lnoload # is valid + l %r1,0xb8 # load ipl subchannel number + la %r2,IPL_BS # load start address + bas %r14,.Lloader # load rest of ipl image + st %r1,__LC_IPLDEV # store ipl device number + l %r12,.Lparm # pointer to parameter area + +# +# load parameter file from ipl device +# +.Lagain1: + l %r2,INITRD_START-PARMAREA(%r12) # use ramdisk location as temp + bas %r14,.Lloader # load parameter file + ltr %r2,%r2 # got anything ? + bz .Lnopf + chi %r2,895 + bnh .Lnotrunc + la %r2,895 +.Lnotrunc: + l %r4,INITRD_START-PARMAREA(%r12) + clc 0(3,%r4),.L_hdr # if it is HDRx + bz .Lagain1 # skip dataset header + clc 0(3,%r4),.L_eof # if it is EOFx + bz .Lagain1 # skip dateset trailer + la %r5,0(%r4,%r2) + lr %r3,%r2 +.Lidebc: + tm 0(%r5),0x80 # high order bit set ? + bo .Ldocv # yes -> convert from EBCDIC + ahi %r5,-1 + bct %r3,.Lidebc + b .Lnocv +.Ldocv: + l %r3,.Lcvtab + tr 0(256,%r4),0(%r3) # convert parameters to ascii + tr 256(256,%r4),0(%r3) + tr 512(256,%r4),0(%r3) + tr 768(122,%r4),0(%r3) +.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line + mvc 0(256,%r3),0(%r4) + mvc 256(256,%r3),256(%r4) + mvc 512(256,%r3),512(%r4) + mvc 768(122,%r3),768(%r4) + slr %r0,%r0 + b .Lcntlp +.Ldelspc: + ic %r0,0(%r2,%r3) + chi %r0,0x20 # is it a space ? + be .Lcntlp + ahi %r2,1 + b .Leolp +.Lcntlp: + brct %r2,.Ldelspc +.Leolp: + slr %r0,%r0 + stc %r0,0(%r2,%r3) # terminate buffer +.Lnopf: + +# +# load ramdisk from ipl device +# +.Lagain2: + l %r2,INITRD_START-PARMAREA(%r12) # load adr. of ramdisk + bas %r14,.Lloader # load ramdisk + st %r2,INITRD_SIZE-PARMAREA(%r12) # store size of ramdisk + ltr %r2,%r2 + bnz .Lrdcont + st %r2,INITRD_START-PARMAREA(%r12) # no ramdisk found, null it +.Lrdcont: + l %r2,INITRD_START-PARMAREA(%r12) + + clc 0(3,%r2),.L_hdr # skip HDRx and EOFx + bz .Lagain2 + clc 0(3,%r2),.L_eof + bz .Lagain2 + +#ifdef CONFIG_IPL_VM +# +# reset files in VM reader +# + stidp __LC_CPUID # store cpuid + lh %r0,__LC_CPUID+4 # get cpu version + chi %r0,0x7490 # running on P/390 ? + be start # no -> skip reset + la %r2,.Lreset + lhi %r3,26 + .long 0x83230008 +#endif + +# +# everything loaded, go for it +# +.Lnoload: + l %r1,.Lstartup + br %r1 + +.Lparm: .long PARMAREA +.Lstartup: .long startup +.Lcvtab:.long _ebcasc # ebcdic to ascii table +.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40 + .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6 + .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold" +.L_eof: .long 0xc5d6c600 /* C'EOF' */ +.L_hdr: .long 0xc8c4d900 /* C'HDR' */ + #endif /* CONFIG_IPL */ # +# SALIPL loader support. Based on a patch by Rob van der Heij. +# This entry point is called directly from the SALIPL loader and +# doesn't need a builtin ipl record. +# + .org 0x800 + .globl start +start: + stm %r0,%r15,0x07b0 # store registers + basr %r12,%r0 +.base: + l %r11,.parm + l %r8,.cmd # pointer to command buffer + + ltr %r9,%r9 # do we have SALIPL parameters? + bp .sk8x8 + + mvc 0(64,%r8),0x00b0 # copy saved registers + xc 64(240-64,%r8),0(%r8) # remainder of buffer + tr 0(64,%r8),.lowcase + b .gotr +.sk8x8: + mvc 0(240,%r8),0(%r9) # copy iplparms into buffer +.gotr: + l %r10,.tbl # EBCDIC to ASCII table + tr 0(240,%r8),0(%r10) + stidp __LC_CPUID # Are we running on VM maybe + cli __LC_CPUID,0xff + bnz .test + .long 0x83300060 # diag 3,0,x'0060' - storage size + b .done +.test: + mvc 0x68(8),.pgmnw # set up pgm check handler + l %r2,.fourmeg + lr %r3,%r2 + bctr %r3,%r0 # 4M-1 +.loop: iske %r0,%r3 + ar %r3,%r2 +.pgmx: + sr %r3,%r2 + la %r3,1(%r3) +.done: + st %r3,MEMORY_SIZE-PARMAREA(%r11) + slr %r0,%r0 + st %r0,INITRD_SIZE-PARMAREA(%r11) + st %r0,INITRD_START-PARMAREA(%r11) + j startup # continue with startup +.tbl: .long _ebcasc # translate table +.cmd: .long COMMAND_LINE # address of command line buffer +.parm: .long PARMAREA +.fourmeg: .long 0x00400000 # 4M +.pgmnw: .long 0x00080000,.pgmx +.lowcase: + .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 + .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f + .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 + .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f + .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 + .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f + .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37 + .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f + .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47 + .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f + .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57 + .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f + .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67 + .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f + .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77 + .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f + + .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87 + .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f + .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97 + .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f + .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 + .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf + .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7 + .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf + .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg + .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf # hi + .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop + .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf # qr + .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 # ..stuvwx + .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef # yz + .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7 + .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff + +# # startup-code at 0x10000, running in real mode -# this is called either by the ipl loader or directly by PSW restart or linload +# this is called either by the ipl loader or directly by PSW restart +# or linload or SALIPL # .org 0x10000 - .globl start -start: basr %r13,0 # get base -.LPG1: lctl %c1,%c1,.Lpstd-.LPG1(%r13) # load pstd - lctl %c7,%c7,.Lpstd-.LPG1(%r13) # load sstd - lctl %c13,%c13,.Lpstd-.LPG1(%r13) # load hstd - lctl %c0,%c0,.Lcr0-.LPG1(%r13) # set CR0 +startup:basr %r13,0 # get base +.LPG1: lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers l %r12,.Lparm1-.LPG1(%r13) # pointer to parameter area # -# find out memory size. That is done in the ipl loader too but for -# ipl from dasd the size of the memory has to be detected too... +# find out memory size. # - icm %r0,15,MEMORY_SIZE-PARMAREA(%r12) - jnz .Lsizeok - mvc 104(8,0),.Lpcmem-.LPG1(%r13) # setup program check handler - slr %r1,%r1 + mvc 104(8),.Lpcmem-.LPG1(%r13) # setup program check handler lhi %r2,1 - sll %r2,20 + sll %r2,17 # test in increments of 128KB + lr %r1,%r2 + ahi %r1,-4 # test last word in the segment .Lloop: - l %r0,0(%r1) # test page - ar %r1,%r2 # add 1M - jnm .Lloop # r1 < 0x80000000 -> loop + l %r0,0(%r1) # test 128KB segment + st %r0,0(%r1) + ar %r1,%r2 # add 128KB + bnm .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop .Lchkmem: n %r1,.L4malign-.LPG1(%r13) # align to multiples of 4M st %r1,MEMORY_SIZE-PARMAREA(%r12) # store memory size .Lsizeok: # +# Now we have to move the ramdisk to a location approriate for the +# memory size. If we have more than 64 MB of memory we move it to 32MB +# to make room for the page tables set up by paging_init. +# + l %r1,MEMORY_SIZE-PARMAREA(%r12) + cl %r1,.Lbigmem-.LPG1(%r13) # memory < 64mb ? + bl .Lnomove-.LPG1(%r13) # if yes ramdisk @8MB is ok + icm %r4,15,INITRD_START-PARMAREA(%r12) + bz .Lnomove-.LPG1(%r13) + l %r2,.Lrdstart-.LPG1(%r13) # new address of ramdisk + st %r2,INITRD_START-PARMAREA(%r12) + l %r1,INITRD_SIZE-PARMAREA(%r12) + ar %r2,%r1 # we start moving at the end + ar %r4,%r1 # because new location > old location +.Lmove: lr %r0,%r2 # new - old is the maximum we can move + sr %r0,%r4 # because of overlapping + cr %r0,%r1 # we shouldn't move more than there is + bnh .Lnoend-.LPG1(%r13) + lr %r0,%r1 +.Lnoend:cl %r0,.Lmaxchunk-.LPG1(%r13) # mvcl can move 2^24-1 in one go + bnh .Lchunk-.LPG1(%r13) + l %r0,.Lmaxchunk-.LPG1(%r13) +.Lchunk:sr %r2,%r0 # make source & destination pointer + sr %r4,%r0 + lr %r3,%r0 # set source & destination length + lr %r5,%r0 + mvcl %r2,%r4 + sr %r2,%r0 # substract length again, since + sr %r4,%r0 # mvcl added it to the pointers + sr %r1,%r0 # substract chunk size from length + bnz .Lmove-.LPG1(%r13) +.Lnomove: + +# # find out if we are running under VM # stidp __LC_CPUID # store cpuid tm __LC_CPUID,0xff # running under VM ? - jno .Lnovm + bno .Lnovm-.LPG1(%r13) oi MACHINE_FLAGS+3-PARMAREA(%r12),1 # set VM flag .Lnovm: lh %r0,__LC_CPUID+4 # get cpu version chi %r0,0x7490 # running on a P/390 ? - jne .Lnop390 + bne .Lnop390-.LPG1(%r13) oi MACHINE_FLAGS+3-PARMAREA(%r12),4 # set P/390 flag .Lnop390: # # find out if we have an IEEE fpu # - mvc 104(8,0),.Lpcfpu-.LPG1(%r13) # setup program check handler + mvc 104(8),.Lpcfpu-.LPG1(%r13) # setup program check handler ld %f0,.Lflt0-.LPG1(%r13) # load (float) 0.0 ldr %f2,%f0 adbr %f0,%f2 # test IEEE add instruction oi MACHINE_FLAGS+3-PARMAREA(%r12),2 # set IEEE fpu flag .Lchkfpu: +# +# find out if we have the CSP instruction +# + mvc 104(8),.Lpccsp-.LPG1(%r13) # setup program check handler + la %r0,0 + lr %r1,%r0 + la %r2,.Lflt0-.LPG1(%r13) + csp %r0,%r2 # Test CSP instruction + oi MACHINE_FLAGS+3-PARMAREA(%r12),8 # set CSP flag +.Lchkcsp: + lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space, # virtual and never return ... .align 8 -.Lentry:.long 0x04080000,0x80000000 + _stext -.Lpstd: .long .Lpgd+0x7F # segment-table -.Lcr0: .long 0x04b50002 +.Lentry:.long 0x00080000,0x80000000 + _stext +.Lctl: .long 0x04b50002 # cr0: various things + .long 0 # cr1: primary space segment table + .long 0 # cr2: access register translation + .long 0 # cr3: instruction authorization + .long 0 # cr4: instruction authorization + .long 0 # cr5: various things + .long 0 # cr6: I/O interrupts + .long 0 # cr7: secondary space segment table + .long 0 # cr8: access registers translation + .long 0 # cr9: tracing off + .long 0 # cr10: tracing off + .long 0 # cr11: tracing off + .long 0 # cr12: tracing off + .long 0 # cr13: home space segment table + .long 0xc0000000 # cr14: machine check handling off + .long 0 # cr15: linkage stack operations .Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem .Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu +.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp .Lflt0: .double 0 .Lparm1:.long PARMAREA .L4malign:.long 0xffc00000 +.Lbigmem:.long 0x04000000 +.Lrdstart:.long 0x02000000 +.Lmaxchunk:.long 0x00ffffff # # params at 10400 (setup.h) @@ -555,17 +591,8 @@ start: basr %r13,0 # get base .word 0 # RAMDISK_FLAGS .org COMMAND_LINE -# .byte "root=/dev/nfs rw nfsroot=9.164.160.7:/home/mschwide/nfsboot " -# .byte "ip=9.164.147.12:9.164.160.7:9.164.147.1:255.255.255.0:vmlinux:tr0:off" -# .byte "root=/dev/nfs nfsroot=9.164.160.7:/home/mschwide/nfsboot " -# .byte "ip=9.164.181.228:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off" -# .byte "root=/dev/nfs nfsroot=9.164.160.7:/home/pasch/nfsboot " -# .byte "ip=9.164.185.120:9.164.160.7:9.164.181.1:255.255.224.0:vmlinux:tr0:off" -# .byte "mdisk=402:65536:1229,403:131072:2780 root=/dev/mnda ro" -# .byte "root=/dev/nfs rw nfsroot=9.164.160.209:/usr/local/nfsboot " -# .byte "ip=9.164.181.228:9.164.160.209:9.164.181.1:255.255.224.0:vmlinux:tr0:off" .byte "root=/dev/ram0 ro" -# .byte 0 + .byte 0 # # startup-code, running in virtual mode @@ -626,43 +653,3 @@ _stext: basr %r13,0 # get base .align 8 .Ldw: .long 0x000a0000,0x00000000 -# -# tempory segment-table at 0x11000 -# - .org 0x11000 -.Lpgd: .long .Lpt0+0x1f # 00000000-000fffff - .long .Lpt1+0x1f # 00100000-001fffff - .long .Lpt2+0x1f # 00200000-002fffff - .long .Lpt3+0x1f # 00300000-003fffff - .fill 2044,4,0x20 # 00400000-7fffffff - -# -# tempory page-tables at 0x12000-0x15fff -# - .macro mktable from,to - .long \from*0x10000 - .long \from*0x10000+0x1000 - .long \from*0x10000+0x2000 - .long \from*0x10000+0x3000 - .long \from*0x10000+0x4000 - .long \from*0x10000+0x5000 - .long \from*0x10000+0x6000 - .long \from*0x10000+0x7000 - .long \from*0x10000+0x8000 - .long \from*0x10000+0x9000 - .long \from*0x10000+0xa000 - .long \from*0x10000+0xb000 - .long \from*0x10000+0xc000 - .long \from*0x10000+0xd000 - .long \from*0x10000+0xe000 - .long \from*0x10000+0xf000 - .if \to-\from - mktable "(\from+1)",\to - .endif - .endm - -.Lpt0: mktable 0,15 -.Lpt1: mktable 16,31 -.Lpt2: mktable 32,47 -.Lpt3: mktable 48,63 - diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index ba513325a..989aa0720 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -20,11 +20,11 @@ #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/timex.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/string.h> #include <linux/random.h> #include <linux/smp.h> -#include <linux/tasks.h> +#include <linux/threads.h> #include <linux/smp_lock.h> #include <linux/init.h> @@ -205,6 +205,8 @@ static inline void wait_on_irq(int cpu) if (!local_bh_count(cpu) && atomic_read(&global_bh_count)) continue; + /* this works even though global_irq_lock not + a long, but is arch-specific --RR */ if (!test_and_set_bit(0,&global_irq_lock)) break; } @@ -243,6 +245,8 @@ void synchronize_irq(void) static inline void get_irqlock(int cpu) { + /* this works even though global_irq_lock not a long, but is + arch-specific --RR */ if (test_and_set_bit(0,&global_irq_lock)) { /* do we already hold the lock? */ if ( cpu == atomic_read(&global_irq_holder)) @@ -398,7 +402,7 @@ void enable_nop(int irq) void __init init_IRQ(void) { - s390_init_IRQ(); + s390_init_IRQ(); } diff --git a/arch/s390/kernel/mathemu.c b/arch/s390/kernel/mathemu.c index 78b6e5ec6..23c6c72a2 100644 --- a/arch/s390/kernel/mathemu.c +++ b/arch/s390/kernel/mathemu.c @@ -9,6 +9,7 @@ * that does not have the IEEE fpu */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/ptrace.h> @@ -16,7 +17,59 @@ #include <asm/uaccess.h> #include <asm/mathemu.h> -static void set_CC_df(__u64 val1,__u64 val2) { +#ifdef CONFIG_SYSCTL +int sysctl_ieee_emulation_warnings=1; +#endif + +#define mathemu_put_user(x, ptr) \ +{ \ + if(put_user((x),(ptr))) \ + return 1; \ +} + +#define mathemu_get_user(x, ptr) \ +{ \ + if(get_user((x),(ptr))) \ + return 1; \ +} + + +#define mathemu_copy_from_user(to,from,n) \ +{ \ + if(copy_from_user((to),(from),(n))==-EFAULT) \ + return 1; \ +} + + +#define mathemu_copy_to_user(to, from, n) \ +{ \ + if(copy_to_user((to),(from),(n))==-EFAULT) \ + return 1; \ +} + + + +static void display_emulation_not_implemented(char *instr) +{ + struct pt_regs *regs; + __u16 *location; + +#if CONFIG_SYSCTL + if(sysctl_ieee_emulation_warnings) +#endif + { + regs=current->thread.regs; + location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + printk("%s ieee fpu instruction not emulated process name: %s pid: %d \n", + instr, + current->comm, current->pid); + printk("%s's PSW: %08lx %08lx\n",instr, + (unsigned long) regs->psw.mask, + (unsigned long) location); + } +} + +static int set_CC_df(__u64 val1,__u64 val2) { int rc; rc = __cmpdf2(val1,val2); current->thread.regs->psw.mask &= 0xFFFFCFFF; @@ -28,9 +81,10 @@ static void set_CC_df(__u64 val1,__u64 val2) { current->thread.regs->psw.mask |= 0x00002000; break; } + return 0; } -static void set_CC_sf(__u32 val1,__u32 val2) { +static int set_CC_sf(__u32 val1,__u32 val2) { int rc; rc = __cmpsf2(val1,val2); current->thread.regs->psw.mask &= 0xFFFFCFFF; @@ -42,384 +96,473 @@ static void set_CC_sf(__u32 val1,__u32 val2) { current->thread.regs->psw.mask |= 0x00002000; break; } + return 0; } -static void emu_adb (int rx, __u64 val) { +static int emu_adb (int rx, __u64 val) { current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,val); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_adbr (int rx, int ry) { +static int emu_adbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d, current->thread.fp_regs.fprs[ry].d); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_aeb (int rx, __u32 val) { +static int emu_aeb (int rx, __u32 val) { current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,val); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_aebr (int rx, int ry) { +static int emu_aebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f, current->thread.fp_regs.fprs[ry].f); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_axbr (int rx, int ry) { - printk("axbr emulation not implemented!\n"); +static int emu_axbr (int rx, int ry) { + display_emulation_not_implemented("axbr"); + return 0; } -static void emu_cdb (int rx, __u64 val) { +static int emu_cdb (int rx, __u64 val) { set_CC_df(current->thread.fp_regs.fprs[rx].d,val); + return 0; } -static void emu_cdbr (int rx, int ry) { +static int emu_cdbr (int rx, int ry) { set_CC_df(current->thread.fp_regs.fprs[rx].d,current->thread.fp_regs.fprs[ry].d); + return 0; } -static void emu_cdfbr (int rx, int ry) { +static int emu_cdfbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __floatsidf(current->thread.regs->gprs[ry]); + return 0; } -static void emu_ceb (int rx, __u32 val) { +static int emu_ceb (int rx, __u32 val) { set_CC_sf(current->thread.fp_regs.fprs[rx].f,val); + return 0; } -static void emu_cebr (int rx, int ry) { +static int emu_cebr (int rx, int ry) { set_CC_sf(current->thread.fp_regs.fprs[rx].f,current->thread.fp_regs.fprs[ry].f); + return 0; } -static void emu_cefbr (int rx, int ry) { +static int emu_cefbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __floatsisf(current->thread.regs->gprs[ry]); + return 0; } -static void emu_cfdbr (int rx, int ry, int mask) { +static int emu_cfdbr (int rx, int ry, int mask) { current->thread.regs->gprs[rx] = __fixdfsi(current->thread.fp_regs.fprs[ry].d); + return 0; } -static void emu_cfebr (int rx, int ry, int mask) { +static int emu_cfebr (int rx, int ry, int mask) { current->thread.regs->gprs[rx] = __fixsfsi(current->thread.fp_regs.fprs[ry].f); + return 0; } -static void emu_cfxbr (int rx, int ry, int mask) { - printk("cfxbr emulation not implemented!\n"); +static int emu_cfxbr (int rx, int ry, int mask) { + display_emulation_not_implemented("cfxbr"); + return 0; } -static void emu_cxbr (int rx, int ry) { - printk("cxbr emulation not implemented!\n"); +static int emu_cxbr (int rx, int ry) { + display_emulation_not_implemented("cxbr"); + return 0; } -static void emu_cxfbr (int rx, int ry) { - printk("cxfbr emulation not implemented!\n"); +static int emu_cxfbr (int rx, int ry) { + display_emulation_not_implemented("cxfbr"); + return 0; } -static void emu_ddb (int rx, __u64 val) { +static int emu_ddb (int rx, __u64 val) { current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,val); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_ddbr (int rx, int ry) { +static int emu_ddbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d, current->thread.fp_regs.fprs[ry].d); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_deb (int rx, __u32 val) { +static int emu_deb (int rx, __u32 val) { current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,val); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_debr (int rx, int ry) { +static int emu_debr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f, current->thread.fp_regs.fprs[ry].f); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_didbr (int rx, int ry, int mask) { - printk("didbr emulation not implemented!\n"); +static int emu_didbr (int rx, int ry, int mask) { + display_emulation_not_implemented("didbr"); + return 0; } -static void emu_diebr (int rx, int ry, int mask) { - printk("diebr emulation not implemented!\n"); +static int emu_diebr (int rx, int ry, int mask) { + display_emulation_not_implemented("diebr"); + return 0; } -static void emu_dxbr (int rx, int ry) { - printk("dxbr emulation not implemented!\n"); +static int emu_dxbr (int rx, int ry) { + display_emulation_not_implemented("dxbr"); + return 0; } -static void emu_efpc (int rx, int ry) { - printk("efpc emulation not implemented!\n"); +static int emu_efpc (int rx, int ry) { + current->thread.regs->gprs[rx]=current->thread.fp_regs.fpc; + return 0; } -static void emu_fidbr (int rx, int ry, int mask) { - printk("fidbr emulation not implemented!\n"); +static int emu_fidbr (int rx, int ry, int mask) { + display_emulation_not_implemented("fidbr"); + return 0; } -static void emu_fiebr (int rx, int ry, int mask) { - printk("fiebr emulation not implemented!\n"); +static int emu_fiebr (int rx, int ry, int mask) { + display_emulation_not_implemented("fiebr"); + return 0; } -static void emu_fixbr (int rx, int ry, int mask) { - printk("fixbr emulation not implemented!\n"); +static int emu_fixbr (int rx, int ry, int mask) { + display_emulation_not_implemented("fixbr"); + return 0; } -static void emu_kdb (int rx, __u64 val) { - printk("kdb emulation not implemented!\n"); +static int emu_kdb (int rx, __u64 val) { + display_emulation_not_implemented("kdb"); + return 0; } -static void emu_kdbr (int rx, int ry) { - printk("kdbr emulation not implemented!\n"); +static int emu_kdbr (int rx, int ry) { + display_emulation_not_implemented("kdbr"); + return 0; } -static void emu_keb (int rx, __u32 val) { - printk("keb emulation not implemented!\n"); +static int emu_keb (int rx, __u32 val) { + display_emulation_not_implemented("keb"); + return 0; } -static void emu_kebr (int rx, int ry) { - printk("kebr emulation not implemented!\n"); +static int emu_kebr (int rx, int ry) { + display_emulation_not_implemented("kebr"); + return 0; } -static void emu_kxbr (int rx, int ry) { - printk("kxbr emulation not implemented!\n"); +static int emu_kxbr (int rx, int ry) { + display_emulation_not_implemented("kxbr"); + return 0; } -static void emu_lcdbr (int rx, int ry) { +static int emu_lcdbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __negdf2(current->thread.fp_regs.fprs[ry].d); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_lcebr (int rx, int ry) { +static int emu_lcebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __negsf2(current->thread.fp_regs.fprs[ry].f); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_lcxbr (int rx, int ry) { - printk("lcxbr emulation not implemented!\n"); +static int emu_lcxbr (int rx, int ry) { + display_emulation_not_implemented("lcxbr"); + return 0; } -static void emu_ldeb (int rx, __u32 val) { +static int emu_ldeb (int rx, __u32 val) { current->thread.fp_regs.fprs[rx].d = __extendsfdf2(val); + return 0; } -static void emu_ldebr (int rx, int ry) { +static int emu_ldebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __extendsfdf2(current->thread.fp_regs.fprs[ry].f); + return 0; } -static void emu_ldxbr (int rx, int ry) { - printk("ldxbr emulation not implemented!\n"); +static int emu_ldxbr (int rx, int ry) { + display_emulation_not_implemented("ldxbr"); + return 0; } -static void emu_ledbr (int rx, int ry) { +static int emu_ledbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __truncdfsf2(current->thread.fp_regs.fprs[ry].d); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_lexbr (int rx, int ry) { - printk("lexbr emulation not implemented!\n"); +static int emu_lexbr (int rx, int ry) { + display_emulation_not_implemented("lexbr"); + return 0; } -static void emu_lndbr (int rx, int ry) { - printk("lndbr emulation not implemented!\n"); +static int emu_lndbr (int rx, int ry) { + display_emulation_not_implemented("lndbr"); + return 0; } -static void emu_lnebr (int rx, int ry) { - printk("lnebr emulation not implemented!\n"); +static int emu_lnebr (int rx, int ry) { + display_emulation_not_implemented("lnebr"); + return 0; } -static void emu_lnxbr (int rx, int ry) { - printk("lnxbr emulation not implemented!\n"); +static int emu_lnxbr (int rx, int ry) { + display_emulation_not_implemented("lnxbr"); + return 0; } -static void emu_lpdbr (int rx, int ry) { +static int emu_lpdbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __absdf2(current->thread.fp_regs.fprs[ry].d); set_CC_df(current->thread.fp_regs.fprs[rx].d,0); + return 0; } -static void emu_lpebr (int rx, int ry) { +static int emu_lpebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __abssf2(current->thread.fp_regs.fprs[ry].f); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_lpxbr (int rx, int ry) { - printk("lpxbr emulation not implemented!\n"); +static int emu_lpxbr (int rx, int ry) { + display_emulation_not_implemented("lpxbr"); + return 0; } -static void emu_ltdbr (int rx, int ry) { +static int emu_ltdbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = current->thread.fp_regs.fprs[ry].d; set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_ltebr (int rx, int ry) { +static int emu_ltebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = current->thread.fp_regs.fprs[ry].f; set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_ltxbr (int rx, int ry) { - printk("ltxbr emulation not implemented!\n"); +static int emu_ltxbr (int rx, int ry) { + display_emulation_not_implemented("ltxbr"); + return 0; } -static void emu_lxdb (int rx, __u64 val) { - printk("lxdb emulation not implemented!\n"); +static int emu_lxdb (int rx, __u64 val) { + display_emulation_not_implemented("lxdb"); + return 0; } -static void emu_lxdbr (int rx, int ry) { - printk("lxdbr emulation not implemented!\n"); +static int emu_lxdbr (int rx, int ry) { + display_emulation_not_implemented("lxdbr"); + return 0; } -static void emu_lxeb (int rx, __u32 val) { - printk("lxeb emulation not implemented!\n"); +static int emu_lxeb (int rx, __u32 val) { + display_emulation_not_implemented("lxeb"); + return 0; } -static void emu_lxebr (int rx, int ry) { - printk("lxebr emulation not implemented!\n"); +static int emu_lxebr (int rx, int ry) { + display_emulation_not_implemented("lxebr"); + return 0; } -static void emu_madb (int rx, __u64 val, int mask) { - printk("madb emulation not implemented!\n"); +static int emu_madb (int rx, __u64 val, int mask) { + display_emulation_not_implemented("madb"); + return 0; } -static void emu_madbr (int rx, int ry, int mask) { - printk(" emulation not implemented!\n"); +static int emu_madbr (int rx, int ry, int mask) { + display_emulation_not_implemented("madbr"); + return 0; } -static void emu_maeb (int rx, __u32 val, int mask) { - printk("maeb emulation not implemented!\n"); +static int emu_maeb (int rx, __u32 val, int mask) { + display_emulation_not_implemented("maeb"); + return 0; } -static void emu_maebr (int rx, int ry, int mask) { - printk("maebr emulation not implemented!\n"); +static int emu_maebr (int rx, int ry, int mask) { + display_emulation_not_implemented("maebr"); + return 0; } -static void emu_mdb (int rx, __u64 val) { +static int emu_mdb (int rx, __u64 val) { current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,val); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_mdbr (int rx, int ry) { +static int emu_mdbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d, current->thread.fp_regs.fprs[ry].d); set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_mdeb (int rx, __u32 val) { - printk("mdeb emulation not implemented!\n"); +static int emu_mdeb (int rx, __u32 val) { + display_emulation_not_implemented("mdeb"); + return 0; } -static void emu_mdebr (int rx, int ry) { - printk("mdebr emulation not implemented!\n"); +static int emu_mdebr (int rx, int ry) { + display_emulation_not_implemented("mdebr"); + return 0; } -static void emu_meeb (int rx, __u32 val) { +static int emu_meeb (int rx, __u32 val) { current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f, val); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_meebr (int rx, int ry) { +static int emu_meebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f, current->thread.fp_regs.fprs[ry].f); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_msdb (int rx, __u64 val, int mask) { - printk("msdb emulation not implemented!\n"); +static int emu_msdb (int rx, __u64 val, int mask) { + display_emulation_not_implemented("msdb"); + return 0; } -static void emu_msdbr (int rx, int ry, int mask) { - printk("msdbr emulation not implemented!\n"); +static int emu_msdbr (int rx, int ry, int mask) { + display_emulation_not_implemented("msdbr"); + return 0; } -static void emu_mseb (int rx, __u32 val, int mask) { - printk("mseb emulation not implemented!\n"); +static int emu_mseb (int rx, __u32 val, int mask) { + display_emulation_not_implemented("mseb"); + return 0; } -static void emu_msebr (int rx, int ry, int mask) { - printk("msebr emulation not implemented!\n"); +static int emu_msebr (int rx, int ry, int mask) { + display_emulation_not_implemented("msebr"); + return 0; } -static void emu_mxbr (int rx, int ry) { - printk("mxbr emulation not implemented!\n"); +static int emu_mxbr (int rx, int ry) { + display_emulation_not_implemented("mxbr"); + return 0; } -static void emu_mxdb (int rx, __u64 val) { - printk("mxdb emulation not implemented!\n"); +static int emu_mxdb (int rx, __u64 val) { + display_emulation_not_implemented("mxdb"); + return 0; } -static void emu_mxdbr (int rx, int ry) { - printk("mxdbr emulation not implemented!\n"); +static int emu_mxdbr (int rx, int ry) { + display_emulation_not_implemented("mxdbr"); + return 0; } -static void emu_sdb (int rx, __u64 val) { +static int emu_sdb (int rx, __u64 val) { current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d, val); set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_sdbr (int rx, int ry) { +static int emu_sdbr (int rx, int ry) { current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d, current->thread.fp_regs.fprs[ry].d); set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL); + return 0; } -static void emu_seb (int rx, __u32 val) { +static int emu_seb (int rx, __u32 val) { current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f, val); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_sebr (int rx, int ry) { +static int emu_sebr (int rx, int ry) { current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f, current->thread.fp_regs.fprs[ry].f); set_CC_sf(current->thread.fp_regs.fprs[rx].f,0); + return 0; } -static void emu_sfpc (int rx, int ry) { - printk("sfpc emulation not implemented!\n"); +static int emu_sfpc (int rx, int ry) { + __u32 val=current->thread.regs->gprs[rx]; + if(val==0) + current->thread.fp_regs.fpc=val; + else + display_emulation_not_implemented("sfpc"); + return 0; } -static void emu_sqdb (int rx, __u64 val) { - printk("sqdb emulation not implemented!\n"); +static int emu_sqdb (int rx, __u64 val) { + display_emulation_not_implemented("sqdb"); + return 0; } -static void emu_sqdbr (int rx, int ry) { - printk("sqdbr emulation not implemented!\n"); +static int emu_sqdbr (int rx, int ry) { + display_emulation_not_implemented("sqdbr"); + return 0; } -static void emu_sqeb (int rx, __u32 val) { - printk("sqeb emulation not implemented!\n"); +static int emu_sqeb (int rx, __u32 val) { + display_emulation_not_implemented("sqeb"); + return 0; } -static void emu_sqebr (int rx, int ry) { - printk("sqebr emulation not implemented!\n"); +static int emu_sqebr (int rx, int ry) { + display_emulation_not_implemented("sqebr"); + return 0; } -static void emu_sqxbr (int rx, int ry) { - printk("sqxbr emulation not implemented!\n"); +static int emu_sqxbr (int rx, int ry) { + display_emulation_not_implemented("sqxbr"); + return 0; } -static void emu_sxbr (int rx, int ry) { - printk("sxbr emulation not implemented!\n"); +static int emu_sxbr (int rx, int ry) { + display_emulation_not_implemented("sxbr"); + return 0; } -static void emu_tcdb (int rx, __u64 val) { - printk("tcdb emulation not implemented!\n"); +static int emu_tcdb (int rx, __u64 val) { + display_emulation_not_implemented("tcdb"); + return 0; } -static void emu_tceb (int rx, __u32 val) { - printk("tceb emulation not implemented!\n"); +static int emu_tceb (int rx, __u32 val) { + display_emulation_not_implemented("tceb"); + return 0; } -static void emu_tcxb (int rx, __u64 val) { - printk("tcxb emulation not implemented!\n"); +static int emu_tcxb (int rx, __u64 val) { + display_emulation_not_implemented("tcxb"); + return 0; } @@ -473,6 +616,7 @@ static inline void emu_store_rege(int reg) { } int math_emu_b3(__u8 *opcode, struct pt_regs * regs) { + int rc=0; static const __u8 format_table[] = { 2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3, @@ -538,84 +682,82 @@ int math_emu_b3(__u8 *opcode, struct pt_regs * regs) { emu_store_regd((opcode[3]>>4)&15); emu_store_regd(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_regd((opcode[3]>>4)&15); - emu_load_regd(opcode[3]&15); - return 0; + emu_load_regd((opcode[3]>>4)&15); + emu_load_regd(opcode[3]&15); + return rc; case 2: /* RRE format, float operation */ emu_store_rege((opcode[3]>>4)&15); emu_store_rege(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - emu_load_rege(opcode[3]&15); - return 0; + emu_load_rege((opcode[3]>>4)&15); + emu_load_rege(opcode[3]&15); + return rc; case 3: /* RRF format, double operation */ emu_store_regd((opcode[3]>>4)&15); emu_store_regd(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - emu_load_regd((opcode[3]>>4)&15); - emu_load_regd(opcode[3]&15); - return 0; + emu_load_regd((opcode[3]>>4)&15); + emu_load_regd(opcode[3]&15); + return rc; case 4: /* RRF format, float operation */ emu_store_rege((opcode[3]>>4)&15); emu_store_rege(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - emu_load_rege((opcode[3]>>4)&15); - emu_load_rege(opcode[3]&15); - return 0; + emu_load_rege((opcode[3]>>4)&15); + emu_load_rege(opcode[3]&15); + return rc; case 5: /* RRE format, cefbr instruction */ emu_store_rege((opcode[3]>>4)&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - return 0; + emu_load_rege((opcode[3]>>4)&15); + return rc; case 6: /* RRE format, cdfbr & cxfbr instruction */ emu_store_regd((opcode[3]>>4)&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_regd((opcode[3]>>4)&15); - return 0; - /* FIXME !! */ - return 0; - case 7: /* RRF format, cfebr instruction */ + emu_load_regd((opcode[3]>>4)&15); + return rc; + case 7: /* RRF format, cfebr instruction */ emu_store_rege(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - return 0; + return rc; case 8: /* RRF format, cfdbr & cfxbr instruction */ emu_store_regd(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15,opcode[2]>>4); - return 0; + return rc; case 9: /* RRE format, ldebr & mdebr instruction */ /* float store but double load */ emu_store_rege((opcode[3]>>4)&15); emu_store_rege(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_regd((opcode[3]>>4)&15); - return 0; + emu_load_regd((opcode[3]>>4)&15); + return rc; case 10: /* RRE format, ledbr instruction */ /* double store but float load */ emu_store_regd((opcode[3]>>4)&15); emu_store_regd(opcode[3]&15); /* call the emulation function */ - ((void (*)(int, int))jump_table[opcode[1]]) + rc=((int (*)(int, int))jump_table[opcode[1]]) (opcode[3]>>4,opcode[3]&15); - emu_load_rege((opcode[3]>>4)&15); - return 0; + emu_load_rege((opcode[3]>>4)&15); + return rc; default: return 1; } @@ -632,6 +774,8 @@ static void* calc_addr(struct pt_regs *regs,int rx,int rb,int disp) } int math_emu_ed(__u8 *opcode, struct pt_regs * regs) { + int rc=0; + static const __u8 format_table[] = { 0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4, 2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3, @@ -669,13 +813,12 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) { emu_store_regd((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if copy_from_user fails ? */ - copy_from_user(&temp, dxb, 8); + mathemu_copy_from_user(&temp, dxb, 8); /* call the emulation function */ - ((void (*)(int, __u64))jump_table[opcode[5]]) + rc=((int (*)(int, __u64))jump_table[opcode[5]]) (opcode[1]>>4,temp); - emu_load_regd((opcode[1]>>4)&15); - return 0; + emu_load_regd((opcode[1]>>4)&15); + return rc; } case 2: /* RXE format, __u32 constant */ { __u32 *dxb, temp; @@ -684,13 +827,12 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) { emu_store_rege((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if get_user fails ? */ - get_user(temp, dxb); + mathemu_get_user(temp, dxb); /* call the emulation function */ - ((void (*)(int, __u32))jump_table[opcode[5]]) + rc=((int (*)(int, __u32))jump_table[opcode[5]]) (opcode[1]>>4,temp); - emu_load_rege((opcode[1]>>4)&15); - return 0; + emu_load_rege((opcode[1]>>4)&15); + return rc; } case 3: /* RXF format, __u64 constant */ { __u32 *dxb, temp; @@ -699,13 +841,12 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) { emu_store_regd((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if copy_from_user fails ? */ - copy_from_user(&temp, dxb, 8); + mathemu_copy_from_user(&temp, dxb, 8); /* call the emulation function */ - ((void (*)(int, __u32, int))jump_table[opcode[5]]) + rc=((int (*)(int, __u32, int))jump_table[opcode[5]]) (opcode[1]>>4,temp,opcode[4]>>4); - emu_load_regd((opcode[1]>>4)&15); - return 0; + emu_load_regd((opcode[1]>>4)&15); + return rc; } case 4: /* RXF format, __u32 constant */ { __u32 *dxb, temp; @@ -714,29 +855,27 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) { emu_store_rege((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if get_user fails ? */ - get_user(temp, dxb); + mathemu_get_user(temp, dxb); /* call the emulation function */ - ((void (*)(int, __u32, int))jump_table[opcode[5]]) + rc=((int (*)(int, __u32, int))jump_table[opcode[5]]) (opcode[1]>>4,temp,opcode[4]>>4); emu_load_rege((opcode[1]>>4)&15); - return 0; + return rc; } case 5: /* RXE format, __u32 constant */ /* store_rege and load_regd */ - { + { __u32 *dxb, temp; __u32 opc; emu_store_rege((opcode[1]>>4)&15); opc = *((__u32 *) opcode); dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if get_user fails ? */ - get_user(temp, dxb); + mathemu_get_user(temp, dxb); /* call the emulation function */ - ((void (*)(int, __u32))jump_table[opcode[5]]) + rc=((int (*)(int, __u32))jump_table[opcode[5]]) (opcode[1]>>4,temp); emu_load_regd((opcode[1]>>4)&15); - return 0; + return rc; } default: return 1; @@ -746,7 +885,7 @@ int math_emu_ed(__u8 *opcode, struct pt_regs * regs) { /* * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6} */ -void math_emu_ldr(__u8 *opcode) { +int math_emu_ldr(__u8 *opcode) { __u16 opc = *((__u16 *) opcode); if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */ @@ -772,12 +911,13 @@ void math_emu_ldr(__u8 *opcode) { current->thread.fp_regs.fprs[(opc&0x00f0)>>4] = current->thread.fp_regs.fprs[opc&0x000f]; } + return 0; } /* * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6} */ -void math_emu_ler(__u8 *opcode) { +int math_emu_ler(__u8 *opcode) { __u16 opc = *((__u16 *) opcode); if ((opc & 0x0090) == 0) { /* test if rx in {0,2,4,6} */ @@ -803,61 +943,68 @@ void math_emu_ler(__u8 *opcode) { current->thread.fp_regs.fprs[(opc&0x00f0)>>4] = current->thread.fp_regs.fprs[opc&0x000f]; } + return 0; } /* * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6} */ -void math_emu_ld(__u8 *opcode, struct pt_regs * regs) { +int math_emu_ld(__u8 *opcode, struct pt_regs * regs) { __u32 opc = *((__u32 *) opcode); __u64 *dxb; dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if copy_from_user fails ? */ - copy_from_user(¤t->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8); + mathemu_copy_from_user(¤t->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8); + return 0; } /* * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6} */ -void math_emu_le(__u8 *opcode, struct pt_regs * regs) { +int math_emu_le(__u8 *opcode, struct pt_regs * regs) { __u32 opc = *((__u32 *) opcode); __u32 *mem, *dxb; dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if get_user fails ? */ mem = (__u32 *) (¤t->thread.fp_regs.fprs[(opc>>20)&15].f); - get_user(mem[0], dxb); + mathemu_get_user(mem[0], dxb); + return 0; } /* * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6} */ -void math_emu_std(__u8 *opcode, struct pt_regs * regs) { +int math_emu_std(__u8 *opcode, struct pt_regs * regs) { __u32 opc = *((__u32 *) opcode); __u64 *dxb; dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if copy_to_user fails ? */ - copy_to_user(dxb, ¤t->thread.fp_regs.fprs[(opc>>20)&15].d, 8); + mathemu_copy_to_user(dxb, ¤t->thread.fp_regs.fprs[(opc>>20)&15].d, 8); + return 0; } /* * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6} */ -void math_emu_ste(__u8 *opcode, struct pt_regs * regs) { +int math_emu_ste(__u8 *opcode, struct pt_regs * regs) { __u32 opc = *((__u32 *) opcode); __u32 *mem, *dxb; dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc); - /* FIXME: how to react if put_user fails ? */ + /* FIXME: how to react if mathemu_put_user fails ? */ mem = (__u32 *) (¤t->thread.fp_regs.fprs[(opc>>20)&15].f); - put_user(mem[0], dxb); + mathemu_put_user(mem[0], dxb); + return 0; } /* * Emulate LFPC D(B) */ int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) { - /* FIXME: how to do that ?!? */ + __u32 *dxb,temp; + __u32 opc = *((__u32 *) opcode); + dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc); + mathemu_get_user(temp, dxb); + if(temp!=0) + display_emulation_not_implemented("lfpc"); return 0; } @@ -865,7 +1012,10 @@ int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) { * Emulate STFPC D(B) */ int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) { - /* FIXME: how to do that ?!? */ + __u32 *dxb; + __u32 opc = *((__u32 *) opcode); + dxb= (__u32 *) calc_addr(regs,0,opc>>12,opc); + mathemu_put_user(current->thread.fp_regs.fpc, dxb); return 0; } @@ -874,6 +1024,7 @@ int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) { */ int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) { /* FIXME: how to do that ?!? */ + display_emulation_not_implemented("srnm"); return 0; } diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 2fc6d08fa..f8238de1e 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -28,7 +28,7 @@ #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/user.h> #include <linux/a.out.h> @@ -67,7 +67,9 @@ int cpu_idle(void *unused) if (softirq_active(smp_processor_id()) & softirq_mask(smp_processor_id())) { do_softirq(); - continue; + __sti(); + if (!current->need_resched) + continue; } if (current->need_resched) { schedule(); @@ -92,12 +94,13 @@ idle_wakeup: 0 returned you know you've got all the lines */ -int sprintf_regs(int line, char *buff, struct task_struct * task, - struct thread_struct *thread, struct pt_regs * regs) -{ +static int sprintf_regs(int line, char *buff, struct task_struct *task, struct pt_regs *regs) +{ int linelen=0; int regno,chaincnt; u32 backchain,prev_backchain,endchain; + u32 ksp = 0; + char *mode = "???"; enum { @@ -118,106 +121,125 @@ int sprintf_regs(int line, char *buff, struct task_struct * task, sp_kern_backchain1 }; - if(task) - thread = &task->thread; - if(thread) - regs = thread->regs; - switch (line) { - case sp_linefeed: + if (task) + ksp = task->thread.ksp; + if (regs && !(regs->psw.mask & PSW_PROBLEM_STATE)) + ksp = regs->gprs[15]; + + if (regs) + mode = (regs->psw.mask & PSW_PROBLEM_STATE)? + "User" : "Kernel"; + + switch(line) + { + case sp_linefeed: linelen=sprintf(buff,"\n"); break; case sp_psw: if(regs) - linelen = sprintf(buff,"User PSW: %08lx %08lx\n", - (unsigned long) regs->psw.mask, - (unsigned long) regs->psw.addr); + linelen=sprintf(buff, "%s PSW: %08lx %08lx\n", mode, + (unsigned long) regs->psw.mask, + (unsigned long) regs->psw.addr); else - linelen = sprintf(buff,"pt_regs=NULL some info unavailable\n"); + linelen=sprintf(buff,"pt_regs=NULL some info unavailable\n"); break; case sp_ksp: - if (task) - linelen += sprintf(&buff[linelen], - "task: %08x ", (addr_t)task); - if (thread) - linelen += sprintf(&buff[linelen], - "thread: %08x ksp: %08x ", - (addr_t)thread,(addr_t)thread->ksp); - if (regs) - linelen += sprintf(&buff[linelen], - "pt_regs: %08x\n", (addr_t)regs); + linelen=sprintf(&buff[linelen], + "task: %08x ksp: %08x pt_regs: %08x\n", + (addr_t)task, (addr_t)ksp, (addr_t)regs); break; case sp_gprs: - if (regs) - linelen = sprintf(buff,"User GPRS:\n"); + if(regs) + linelen=sprintf(buff, "%s GPRS:\n", mode); break; case sp_gprs1 ... sp_gprs4: - if (regs) { - regno = (line-sp_gprs1)*4; - linelen = sprintf(buff,"%08x %08x %08x %08x\n", - regs->gprs[regno], - regs->gprs[regno+1], - regs->gprs[regno+2], - regs->gprs[regno+3]); + if(regs) + { + regno=(line-sp_gprs1)*4; + linelen=sprintf(buff,"%08x %08x %08x %08x\n", + regs->gprs[regno], + regs->gprs[regno+1], + regs->gprs[regno+2], + regs->gprs[regno+3]); } break; case sp_acrs: - if (regs) - linelen = sprintf(buff,"User ACRS:\n"); + if(regs) + linelen=sprintf(buff, "%s ACRS:\n", mode); break; case sp_acrs1 ... sp_acrs4: - if (regs) { - regno = (line-sp_acrs1)*4; - linelen = sprintf(buff,"%08x %08x %08x %08x\n", - regs->acrs[regno], - regs->acrs[regno+1], - regs->acrs[regno+2], - regs->acrs[regno+3]); + if(regs) + { + regno=(line-sp_acrs1)*4; + linelen=sprintf(buff,"%08x %08x %08x %08x\n", + regs->acrs[regno], + regs->acrs[regno+1], + regs->acrs[regno+2], + regs->acrs[regno+3]); } break; case sp_kern_backchain: - if (thread && thread->ksp && regs) - linelen = sprintf(buff,"Kernel BackChain CallChain BackChain CallChain\n"); + if (regs && (regs->psw.mask & PSW_PROBLEM_STATE)) + break; + if (ksp) + linelen=sprintf(buff, "Kernel BackChain CallChain\n"); break; default: - if(thread && thread->ksp && regs) { - backchain = (thread->ksp & PSW_ADDR_MASK); - endchain = ((backchain & (-8192)) + 8192); - prev_backchain = backchain - 1; - line -= sp_kern_backchain1; - for (chaincnt = 0; ; chaincnt++) { - if ((backchain == 0) || - (backchain >= endchain) || - (chaincnt >= 8) || - (prev_backchain >= backchain)) + if (ksp) + { + + backchain=ksp&PSW_ADDR_MASK; + endchain=((backchain&(-8192))+8192); + prev_backchain=backchain-1; + line-=sp_kern_backchain1; + for(chaincnt=0;;chaincnt++) + { + if((backchain==0)||(backchain>=endchain) + ||(chaincnt>=8)||(prev_backchain>=backchain)) break; - if ((chaincnt >> 1) == line) { - linelen += sprintf(&buff[linelen],"%s%08x %08x ", - (chaincnt&1) ? "":" ", - backchain,*(u32 *)(backchain+56)); - } - if ((chaincnt >> 1) > line) + if(chaincnt==line) + { + linelen+=sprintf(&buff[linelen]," %08x [<%08lx>]\n", + backchain, + *(u32 *)(backchain+56)&PSW_ADDR_MASK); break; - prev_backchain = backchain; - backchain = (*((u32 *)backchain)) & PSW_ADDR_MASK; + } + prev_backchain=backchain; + backchain=(*((u32 *)backchain))&PSW_ADDR_MASK; } - if (linelen) - linelen += sprintf(&buff[linelen],"\n"); } } - return linelen; + return(linelen); } -void show_regs(struct task_struct *task, struct thread_struct *thread, - struct pt_regs *regs) +void show_regs(struct pt_regs *regs) { char buff[80]; int line; + + printk("CPU: %d\n",smp_processor_id()); + printk("Process %s (pid: %d, stackpage=%08X)\n", + current->comm, current->pid, 4096+(addr_t)current); - for (line = 0; sprintf_regs(line,buff,task,thread,regs); line++) + for (line = 0; sprintf_regs(line, buff, current, regs); line++) printk(buff); } +char *task_show_regs(struct task_struct *task, char *buffer) +{ + int line, len; + + for (line = 0; ; line++) + { + len = sprintf_regs(line, buffer, task, task->thread.regs); + if (!len) break; + buffer += len; + } + return buffer; +} + + int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { int clone_arg = flags | CLONE_VM; @@ -327,7 +349,7 @@ asmlinkage int sys_clone(struct pt_regs regs) lock_kernel(); clone_flags = regs.gprs[3]; - newsp = regs.gprs[2]; + newsp = regs.orig_gpr2; if (!newsp) newsp = regs.gprs[15]; ret = do_fork(clone_flags, newsp, ®s, 0); @@ -365,7 +387,19 @@ asmlinkage int sys_execve(struct pt_regs regs) goto out; error = do_execve(filename, (char **) regs.gprs[3], (char **) regs.gprs[4], ®s); if (error == 0) - current->flags &= ~PF_DTRACE; + { + 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"); + } + } putname(filename); out: return error; @@ -412,21 +446,77 @@ extern void scheduling_functions_end_here(void); unsigned long get_wchan(struct task_struct *p) { - unsigned long r14, r15; + unsigned long r14, r15, bc; unsigned long stack_page; int count = 0; if (!p || p == current || p->state == TASK_RUNNING) return 0; stack_page = (unsigned long) p; r15 = p->thread.ksp; + if (!stack_page || r15 < stack_page || r15 >= 8188+stack_page) + return 0; + bc = (*(unsigned long *) r15) & 0x7fffffff; do { - r14 = *(unsigned long *) (r15+56); + if (bc < stack_page || bc >= 8188+stack_page) + return 0; + r14 = (*(unsigned long *) (bc+56)) & 0x7fffffff; if (r14 < first_sched || r14 >= last_sched) return r14; - r15 = *(unsigned long *) (r15+60); + bc = (*(unsigned long *) bc) & 0x7fffffff; } while (count++ < 16); return 0; } #undef last_sched #undef first_sched +/* + * This should be safe even if called from tq_scheduler + * A typical mask would be sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM) or 0. + * + */ +void s390_daemonize(char *name,unsigned long mask,int use_init_fs) +{ + struct fs_struct *fs; + extern struct task_struct *child_reaper; + struct task_struct *this_process=current; + + /* + * If we were started as result of loading a module, close all of the + * user space pages. We don't need them, and if we didn't close them + * they would be locked into memory. + */ + exit_mm(current); + + this_process->session = 1; + this_process->pgrp = 1; + if(name) + { + strncpy(current->comm,name,15); + current->comm[15]=0; + } + else + current->comm[0]=0; + /* set signal mask to what we want to respond */ + siginitsetinv(¤t->blocked,mask); + /* exit_signal isn't set up */ + /* if we inherit from cpu idle */ + this_process->exit_signal=SIGCHLD; + /* if priority=0 schedule can go into a tight loop */ + this_process->policy= SCHED_OTHER; + /* nice goes priority=20-nice; */ + this_process->nice=10; + if(use_init_fs) + { + exit_fs(this_process); /* current->fs->count--; */ + fs = init_task.fs; + current->fs = fs; + atomic_inc(&fs->count); + exit_files(current); + } + write_lock_irq(&tasklist_lock); + /* We want init as our parent */ + REMOVE_LINKS(this_process); + this_process->p_opptr=this_process->p_pptr=child_reaper; + SET_LINKS(this_process); + write_unlock_irq(&tasklist_lock); +} diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 2643f100a..29a81418a 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -66,10 +66,16 @@ void FixPerRegisters(struct task_struct *task) regs->psw.mask |=PSW_PER_MASK; else regs->psw.mask &= ~PSW_PER_MASK; - if(per_info->control_regs.bits.storage_alt_space_ctl) - task->thread.user_seg|=USER_STD_MASK; + if (per_info->control_regs.bits.em_storage_alteration) + { + per_info->control_regs.bits.storage_alt_space_ctl=1; + //((pgd_t *)__pa(task->mm->pgd))->pgd |= USER_STD_MASK; + } else - task->thread.user_seg&=~USER_STD_MASK; + { + per_info->control_regs.bits.storage_alt_space_ctl=0; + //((pgd_t *)__pa(task->mm->pgd))->pgd &= ~USER_STD_MASK; + } } void set_single_step(struct task_struct *task) @@ -209,10 +215,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) if (request == PTRACE_TRACEME) { /* are we already being traced? */ - if (current->flags & PF_PTRACED) + if (current->ptrace & PT_PTRACED) goto out; /* set the ptrace bit in the process flags. */ - current->flags |= PF_PTRACED; + current->ptrace |= PT_PTRACED; ret = 0; goto out; } @@ -237,9 +243,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) (current->gid != child->sgid)) && !capable(CAP_SYS_PTRACE)) goto out; /* the same process cannot be attached many times */ - if (child->flags & PF_PTRACED) + if (child->ptrace & PT_PTRACED) goto out; - child->flags |= PF_PTRACED; + child->ptrace |= PT_PTRACED; write_lock_irqsave(&tasklist_lock, flags); if (child->p_pptr != current) @@ -256,16 +262,20 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) } ret = -ESRCH; // printk("child=%lX child->flags=%lX",child,child->flags); - if (!(child->flags & PF_PTRACED)) - goto out; - if (child->state != TASK_STOPPED) + /* I added child!=current line so we can get the */ + /* ieee_instruction_pointer from the user structure DJB */ + if(child!=current) { - if (request != PTRACE_KILL) + if (!(child->ptrace & PT_PTRACED)) + goto out; + if (child->state != TASK_STOPPED) + { + if (request != PTRACE_KILL) + goto out; + } + if (child->p_pptr != current) goto out; } - if (child->p_pptr != current) - goto out; - switch (request) { /* If I and D space are separate, these will need to be fixed. */ @@ -303,9 +313,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) if ((unsigned long) data >= _NSIG) break; if (request == PTRACE_SYSCALL) - child->flags |= PF_TRACESYS; + child->ptrace |= PT_TRACESYS; else - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; /* make sure the single step bit is not set. */ clear_single_step(child); @@ -332,7 +342,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; if ((unsigned long) data >= _NSIG) break; - child->flags &= ~PF_TRACESYS; + child->ptrace &= ~PT_TRACESYS; child->exit_code = data; set_single_step(child); /* give it a chance to run. */ @@ -344,7 +354,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = -EIO; if ((unsigned long) data >= _NSIG) break; - child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->ptrace &= ~(PT_PTRACED|PT_TRACESYS); child->exit_code = data; write_lock_irqsave(&tasklist_lock, flags); REMOVE_LINKS(child); @@ -374,11 +384,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) asmlinkage void syscall_trace(void) { lock_kernel(); - if ((current->flags & (PF_PTRACED|PF_TRACESYS)) - != (PF_PTRACED|PF_TRACESYS)) + if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) + != (PT_PTRACED|PT_TRACESYS)) goto out; current->exit_code = SIGTRAP; - current->state = TASK_STOPPED; + set_current_state(TASK_STOPPED); notify_parent(current, SIGCHLD); schedule(); /* diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S index a77940905..c30fe433c 100644 --- a/arch/s390/kernel/reipl.S +++ b/arch/s390/kernel/reipl.S @@ -1,4 +1,13 @@ +/* + * arch/s390/kernel/reipl.S + * + * S390 version + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com) + */ + #include <asm/lowcore.h> + .globl do_reipl do_reipl: basr %r13,0 .Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) @@ -7,7 +16,7 @@ do_reipl: basr %r13,0 ni .Lctlsave-.Lpg0(%r13),0xef lctl %c0,%c0,.Lctlsave-.Lpg0(%r13) lr %r1,%r2 - mvc __LC_PGM_NEW_PSW(8,0),.Lpcnew-.Lpg0(%r13) + mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13) stsch .Lschib-.Lpg0(%r13) oi .Lschib+5-.Lpg0(%r13),0x84 .Lecs: xi .Lschib+27-.Lpg0(%r13),0x01 @@ -15,9 +24,9 @@ do_reipl: basr %r13,0 ssch .Liplorb-.Lpg0(%r13) jz .L001 bas %r14,.Ldisab-.Lpg0(%r13) -.L001: mvc __LC_IO_NEW_PSW(8,0),.Lionew-.Lpg0(%r13) +.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13) .Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13) -.Lcont: c %r1,__LC_SUBCHANNEL_ID(%r0) +.Lcont: c %r1,__LC_SUBCHANNEL_ID jnz .Ltpi clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13) jnz .Ltpi @@ -29,7 +38,7 @@ do_reipl: basr %r13,0 jz .L003 bas %r14,.Ldisab-.Lpg0(%r13) .L003: spx .Lnull-.Lpg0(%r13) - st %r1,__LC_SUBCHANNEL_ID(%r0) + st %r1,__LC_SUBCHANNEL_ID lpsw 0 sigp 0,0,0(6) .Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c new file mode 100644 index 000000000..6a7be9496 --- /dev/null +++ b/arch/s390/kernel/s390_ext.c @@ -0,0 +1,77 @@ +/* + * arch/s390/kernel/s390_ext.c + * + * S390 version + * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com), + * Martin Schwidefsky (schwidefsky@de.ibm.com) + */ + +#include <linux/kernel.h> +#include <linux/malloc.h> +#include <asm/lowcore.h> +#include <asm/s390_ext.h> + +/* + * Simple hash strategy: index = code & 0xff; + * ext_int_hash[index] is the start of the list for all external interrupts + * that hash to this index. With the current set of external interrupts + * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000 + * iucv) this is always the first element. + */ +ext_int_info_t *ext_int_hash[256] = { 0, }; +ext_int_info_t ext_int_info_timer; +ext_int_info_t ext_int_info_hwc; + +int register_external_interrupt(__u16 code, ext_int_handler_t handler) { + ext_int_info_t *p; + int index; + + index = code & 0xff; + p = ext_int_hash[index]; + while (p != NULL) { + if (p->code == code) + return -EBUSY; + p = p->next; + } + if (code == 0x1004) /* time_init is done before kmalloc works :-/ */ + p = &ext_int_info_timer; + else if (code == 0x2401) /* hwc_init is done too early too */ + p = &ext_int_info_hwc; + else + p = (ext_int_info_t *) + kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC); + if (p == NULL) + return -ENOMEM; + p->code = code; + p->handler = handler; + p->next = ext_int_hash[index]; + ext_int_hash[index] = p; + return 0; +} + +int unregister_external_interrupt(__u16 code, ext_int_handler_t handler) { + ext_int_info_t *p, *q; + int index; + + index = code & 0xff; + q = NULL; + p = ext_int_hash[index]; + while (p != NULL) { + if (p->code == code && p->handler == handler) + break; + q = p; + p = p->next; + } + if (p == NULL) + return -ENOENT; + if (q != NULL) + q->next = p->next; + else + ext_int_hash[index] = p->next; + if (code != 0x1004 && code != 0x2401) + kfree(p); + return 0; +} + + diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index 85ecb5ce0..b0a6d0225 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -5,14 +5,27 @@ */ #include <linux/config.h> #include <linux/module.h> +#include <linux/string.h> +#include <asm/ccwcache.h> +#include <asm/debug.h> #include <asm/irq.h> -#include <asm/string.h> +#include <asm/s390_ext.h> +#include <asm/s390dyn.h> +#include <asm/ebcdic.h> #include <asm/checksum.h> +#include <asm/delay.h> +#if CONFIG_CHANDEV +#include <asm/chandev.h> +#endif +#if CONFIG_IP_MULTICAST +#include <net/arp.h> +#endif /* * I/O subsystem */ EXPORT_SYMBOL(halt_IO); +EXPORT_SYMBOL(clear_IO); EXPORT_SYMBOL(do_IO); EXPORT_SYMBOL(resume_IO); EXPORT_SYMBOL(ioinfo); @@ -22,6 +35,35 @@ EXPORT_SYMBOL(get_irq_by_devno); EXPORT_SYMBOL(get_devno_by_irq); EXPORT_SYMBOL(get_irq_first); EXPORT_SYMBOL(get_irq_next); +EXPORT_SYMBOL(read_conf_data); +EXPORT_SYMBOL(read_dev_chars); +EXPORT_SYMBOL(s390_request_irq_special); +EXPORT_SYMBOL(s390_device_register); +EXPORT_SYMBOL(s390_device_unregister); + +EXPORT_SYMBOL(ccw_alloc_request); +EXPORT_SYMBOL(ccw_free_request); + +EXPORT_SYMBOL(register_external_interrupt); +EXPORT_SYMBOL(unregister_external_interrupt); + +/* + * debug feature + */ +EXPORT_SYMBOL(debug_register); +EXPORT_SYMBOL(debug_unregister); +EXPORT_SYMBOL(debug_set_level); +EXPORT_SYMBOL(debug_register_view); +EXPORT_SYMBOL(debug_unregister_view); +EXPORT_SYMBOL(debug_event); +EXPORT_SYMBOL(debug_int_event); +EXPORT_SYMBOL(debug_text_event); +EXPORT_SYMBOL(debug_exception); +EXPORT_SYMBOL(debug_int_exception); +EXPORT_SYMBOL(debug_text_exception); +EXPORT_SYMBOL(debug_hex_ascii_view); +EXPORT_SYMBOL(debug_raw_view); +EXPORT_SYMBOL(debug_dflt_header_fn); /* * memory management @@ -29,6 +71,16 @@ EXPORT_SYMBOL(get_irq_next); EXPORT_SYMBOL(_oi_bitmap); EXPORT_SYMBOL(_ni_bitmap); EXPORT_SYMBOL(_zb_findmap); +EXPORT_SYMBOL(__copy_from_user_fixup); +EXPORT_SYMBOL(__copy_to_user_fixup); + +/* + * semaphore ops + */ +EXPORT_SYMBOL(__up); +EXPORT_SYMBOL(__down); +EXPORT_SYMBOL(__down_interruptible); +EXPORT_SYMBOL(__down_trylock); /* * string functions @@ -36,6 +88,7 @@ EXPORT_SYMBOL(_zb_findmap); EXPORT_SYMBOL_NOVERS(memcmp); EXPORT_SYMBOL_NOVERS(memset); EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL_NOVERS(strlen); EXPORT_SYMBOL_NOVERS(strchr); EXPORT_SYMBOL_NOVERS(strcmp); EXPORT_SYMBOL_NOVERS(strncat); @@ -46,19 +99,42 @@ EXPORT_SYMBOL_NOVERS(strrchr); EXPORT_SYMBOL_NOVERS(strtok); EXPORT_SYMBOL_NOVERS(strpbrk); +EXPORT_SYMBOL_NOVERS(_ascebc_500); +EXPORT_SYMBOL_NOVERS(_ebcasc_500); +EXPORT_SYMBOL_NOVERS(_ascebc); +EXPORT_SYMBOL_NOVERS(_ebcasc); +EXPORT_SYMBOL_NOVERS(_ebc_tolower); +EXPORT_SYMBOL_NOVERS(_ebc_toupper); + /* * misc. */ +EXPORT_SYMBOL(module_list); +EXPORT_SYMBOL(__udelay); #ifdef CONFIG_SMP #include <asm/smplock.h> EXPORT_SYMBOL(__global_cli); EXPORT_SYMBOL(__global_sti); EXPORT_SYMBOL(__global_save_flags); EXPORT_SYMBOL(__global_restore_flags); +EXPORT_SYMBOL(lowcore_ptr); EXPORT_SYMBOL(global_bh_lock); EXPORT_SYMBOL(kernel_flag); +EXPORT_SYMBOL(smp_ctl_set_bit); +EXPORT_SYMBOL(smp_ctl_clear_bit); #endif EXPORT_SYMBOL(kernel_thread); EXPORT_SYMBOL(csum_fold); - +#if CONFIG_CHANDEV +EXPORT_SYMBOL(chandev_register_and_probe); +EXPORT_SYMBOL(chandev_request_irq); +EXPORT_SYMBOL(chandev_unregister); +EXPORT_SYMBOL(chandev_initdevice); +EXPORT_SYMBOL(chandev_initnetdevice); +#endif +#if CONFIG_IP_MULTICAST +/* Required for lcs gigabit ethernet multicast support */ +EXPORT_SYMBOL(arp_mc_map); +#endif +EXPORT_SYMBOL(s390_daemonize); diff --git a/arch/s390/kernel/s390dyn.c b/arch/s390/kernel/s390dyn.c deleted file mode 100644 index 0a5625830..000000000 --- a/arch/s390/kernel/s390dyn.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * arch/s390/kernel/s390dyn.c - * S/390 dynamic device attachment - * - * S390 version - * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Ingo Adlung (adlung@de.ibm.com) - */ - -#include <linux/init.h> - -#include <asm/irq.h> -#include <asm/s390io.h> -#include <asm/s390dyn.h> - -int s390_device_register( devreg_t *drinfo ) -{ - return -EOPNOTSUPP; -} - - -int s390_device_deregister ( devreg_t *dreg ) -{ - return -EOPNOTSUPP; -} - -int s390_request_irq_special( int irq, - io_handler_func_t io_handler, - not_oper_handler_func_t not_oper_handler, - unsigned long irqflags, - const char *devname, - void *dev_id) -{ - return -EOPNOTSUPP; -} - diff --git a/arch/s390/kernel/s390fpu.c b/arch/s390/kernel/s390fpu.c index 42048abbc..c56c50d66 100644 --- a/arch/s390/kernel/s390fpu.c +++ b/arch/s390/kernel/s390fpu.c @@ -81,6 +81,11 @@ 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" diff --git a/arch/s390/kernel/s390io.c b/arch/s390/kernel/s390io.c deleted file mode 100644 index b1db16707..000000000 --- a/arch/s390/kernel/s390io.c +++ /dev/null @@ -1,4605 +0,0 @@ -/* - * arch/s390/kernel/s390io.c - * S/390 common I/O routines - * - * S390 version - * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, - * IBM Corporation - * Author(s): Ingo Adlung (adlung@de.ibm.com) - */ - -#include <linux/config.h> -#include <linux/errno.h> -#include <linux/kernel_stat.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/malloc.h> -#include <linux/string.h> -#include <linux/smp.h> -#include <linux/tasks.h> -#include <linux/smp_lock.h> -#include <linux/init.h> -#include <linux/bootmem.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/processor.h> -#include <asm/lowcore.h> - -#include <asm/s390io.h> -#include <asm/s390dyn.h> -#include <asm/s390mach.h> - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -#undef CONFIG_DEBUG_IO - -#define REIPL_DEVID_MAGIC 0x87654321 - -struct irqaction init_IRQ_action; -unsigned int highest_subchannel; -ioinfo_t *ioinfo_head = NULL; -ioinfo_t *ioinfo_tail = NULL; -ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = { - [0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA -}; - -static spinlock_t sync_isc; // synchronous irq processing lock -static psw_t io_sync_wait; // wait PSW for sync IO, prot. by sync_isc -static psw_t io_new_psw; // save I/O new PSW, prot. by sync_isc -static int cons_dev = -1; // identify console device -static int init_IRQ_complete = 0; -static schib_t init_schib; -static __u64 irq_IPL_TOD; - -/* - * Dummy controller type for unused interrupts - */ -int do_none(unsigned int irq, int cpu, struct pt_regs * regs) { return 0;} -int enable_none(unsigned int irq) { return(-ENODEV); } -int disable_none(unsigned int irq) { return(-ENODEV); } - -struct hw_interrupt_type no_irq_type = { - "none", - do_none, - enable_none, - disable_none -}; - -static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs); -static int s390_setup_irq(unsigned int irq, struct irqaction * new); -static void s390_process_subchannels( void); -static void s390_device_recognition( void); -static int s390_validate_subchannel( int irq); -static int s390_SenseID( int irq, senseid_t *sid); -static int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid); -static int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid); -static int s390_process_IRQ( unsigned int irq ); -static int s390_DevicePathVerification( int irq ); - -extern int do_none(unsigned int irq, int cpu, struct pt_regs * regs); -extern int enable_none(unsigned int irq); -extern int disable_none(unsigned int irq); -extern void tod_wait(unsigned long usecs); - -asmlinkage void do_IRQ( struct pt_regs regs, - unsigned int irq, - __u32 s390_intparm ); - -void s390_displayhex(char *str,void *ptr,s32 cnt); - -void s390_displayhex(char *str,void *ptr,s32 cnt) -{ - s32 cnt1,cnt2,maxcnt2; - u32 *currptr=(__u32 *)ptr; - - printk("\n%s\n",str); - - for(cnt1=0;cnt1<cnt;cnt1+=16) - { - printk("%08lX ",(unsigned long)currptr); - maxcnt2=cnt-cnt1; - if(maxcnt2>16) - maxcnt2=16; - for(cnt2=0;cnt2<maxcnt2;cnt2+=4) - printk("%08X ",*currptr++); - printk("\n"); - } -} - -int s390_request_irq( unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long irqflags, - const char *devname, - void *dev_id) -{ - int retval; - struct irqaction *action; - - if (irq >= __MAX_SUBCHANNELS) - return -EINVAL; - - if ( !handler || !dev_id ) - return -EINVAL; - - /* - * during init_IRQ() processing we don't have memory - * management yet, thus need to use a statically - * allocated irqaction control block - */ - if ( init_IRQ_complete ) - { - action = (struct irqaction *) - kmalloc(sizeof(struct irqaction), GFP_KERNEL); - } - else - { - action = &init_IRQ_action; - - } /* endif */ - - if (!action) - { - return -ENOMEM; - - } /* endif */ - - action->handler = handler; - action->flags = irqflags; - action->mask = 0; - action->name = devname; - action->next = NULL; - action->dev_id = dev_id; - - retval = s390_setup_irq( irq, action); - - if ( !retval ) - { - retval = s390_DevicePathVerification( irq ); - } - else if ( retval && init_IRQ_complete ) - { - kfree(action); - - } /* endif */ - - return retval; -} - -void s390_free_irq(unsigned int irq, void *dev_id) -{ - unsigned int flags; - int ret; - - unsigned int count = 0; - - if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return; - - } /* endif */ - - s390irq_spin_lock_irqsave( irq, flags); - -#ifdef CONFIG_KERNEL_DEBUG - if ( irq != cons_dev ) - { - printk("Trying to free IRQ%d\n",irq); - - } /* endif */ -#endif - - /* - * disable the device and reset all IRQ info if - * the IRQ is actually owned by the handler ... - */ - if ( ioinfo[irq]->irq_desc.action ) - { - if ( (dev_id == ioinfo[irq]->irq_desc.action->dev_id ) - || (dev_id == (devstat_t *)REIPL_DEVID_MAGIC) ) - { - /* start deregister */ - ioinfo[irq]->ui.flags.unready = 1; - - do - { - ret = ioinfo[irq]->irq_desc.handler->disable(irq); - - count++; - - if ( ret == -EBUSY ) - { - int iret; - - /* - * kill it ! - * ... we first try sync and eventually - * try terminating the current I/O by - * an async request, twice halt, then - * clear. - */ - if ( count < 3 ) - { - iret = halt_IO( irq, - 0xC8C1D3E3, - DOIO_WAIT_FOR_INTERRUPT ); - - if ( iret == -EBUSY ) - { - halt_IO( irq, 0xC8C1D3E3, 0); - s390irq_spin_unlock_irqrestore( irq, flags); - tod_wait( 200000 ); /* 200 ms */ - s390irq_spin_lock_irqsave( irq, flags); - - } /* endif */ - } - else - { - iret = clear_IO( irq, - 0x40C3D3D9, - DOIO_WAIT_FOR_INTERRUPT ); - - if ( iret == -EBUSY ) - { - clear_IO( irq, 0xC8C1D3E3, 0); - s390irq_spin_unlock_irqrestore( irq, flags); - tod_wait( 1000000 ); /* 1000 ms */ - s390irq_spin_lock_irqsave( irq, flags); - - } /* endif */ - - } /* endif */ - - if ( count == 3 ) - { - /* give it a very last try ... */ - ioinfo[irq]->irq_desc.handler->disable(irq); - - if ( ioinfo[irq]->ui.flags.busy ) - { - printk( KERN_CRIT"free_irq(%04X) " - "- device %04X busy, retry " - "count exceeded\n", - irq, - ioinfo[irq]->devstat.devno); - - } /* endif */ - - break; /* sigh, let's give up ... */ - - } /* endif */ - - } /* endif */ - - } while ( ret == -EBUSY ); - - if ( init_IRQ_complete ) - kfree( ioinfo[irq]->irq_desc.action ); - - ioinfo[irq]->irq_desc.action = NULL; - ioinfo[irq]->ui.flags.ready = 0; - - ioinfo[irq]->irq_desc.handler->enable = &enable_none; - ioinfo[irq]->irq_desc.handler->disable = &disable_none; - - ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */ - - s390irq_spin_unlock_irqrestore( irq, flags); - } - else - { - s390irq_spin_unlock_irqrestore( irq, flags); - - printk("free_irq() : error, dev_id does not match !"); - - } /* endif */ - - } - else - { - s390irq_spin_unlock_irqrestore( irq, flags); - - printk("free_irq() : error, no action block ... !"); - - } /* endif */ - -} - -/* - * Generic enable/disable code - */ -int disable_irq(unsigned int irq) -{ - unsigned long flags; - int ret; - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - return( -ENODEV); - - s390irq_spin_lock_irqsave(irq, flags); - - /* - * At this point we may actually have a pending interrupt being active - * on another CPU. So don't touch the IRQ_INPROGRESS bit.. - */ - ioinfo[irq]->irq_desc.status |= IRQ_DISABLED; - ret = ioinfo[irq]->irq_desc.handler->disable(irq); - s390irq_spin_unlock_irqrestore(irq, flags); - - synchronize_irq(); - - return( ret); -} - -int enable_irq(unsigned int irq) -{ - unsigned long flags; - int ret; - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - return( -ENODEV); - - s390irq_spin_lock_irqsave(irq, flags); - - ioinfo[irq]->irq_desc.status = 0; - ret = ioinfo[irq]->irq_desc.handler->enable(irq); - - s390irq_spin_unlock_irqrestore(irq, flags); - - return(ret); -} - -/* - * Enable IRQ by modifying the subchannel - */ -static int enable_subchannel( unsigned int irq) -{ - int ret; - int ccode; - int retry = 5; - - if ( irq > highest_subchannel || irq < 0 ) - { - return( -ENODEV ); - - } /* endif */ - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - return( -ENODEV); - - /* - * If a previous disable request is pending we reset it. However, this - * status implies that the device may (still) be not-operational. - */ - if ( ioinfo[irq]->ui.flags.d_disable ) - { - ioinfo[irq]->ui.flags.d_disable = 0; - ret = 0; - } - else - { - - ccode = stsch(irq, &(ioinfo[irq]->schib) ); - - if ( ccode ) - { - ret = -ENODEV; - } - else - { - ioinfo[irq]->schib.pmcw.ena = 1; - - do - { - ccode = msch( irq, &(ioinfo[irq]->schib) ); - - switch (ccode) { - case 0: - ret = 0; - break; - - case 1: - /* - * very bad, requires interrupt alike - * processing, where "rbh" is a dummy - * parameter for interface compatibility - * only. Bottom-half handling cannot be - * required as this must be an - * unsolicited interrupt (!busy). - */ - - ioinfo[irq]->ui.flags.s_pend = 1; - - s390_process_IRQ( irq ); - - ioinfo[irq]->ui.flags.s_pend = 0; - - ret = -EIO; /* might be overwritten */ - /* ... on re-driving */ - /* ... the msch() */ - retry--; - break; - - case 3: - ioinfo[irq]->ui.flags.oper = 0; - ret = -ENODEV; - break; - - default: - printk( KERN_CRIT"enable_subchannel(%04X) " - " : ccode 2 on msch() for device " - "%04X received !\n", - irq, - ioinfo[irq]->devstat.devno); - ret = -ENODEV; // never reached - } - - } while ( (ccode == 1) && retry ); - - } /* endif */ - - } /* endif */ - - return( ret ); -} - - -/* - * Disable IRQ by modifying the subchannel - */ -static int disable_subchannel( unsigned int irq) -{ - int cc; /* condition code */ - int ret; /* function return value */ - int retry = 5; - - if ( irq > highest_subchannel ) - { - ret = -ENODEV; - } - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - else if ( ioinfo[irq]->ui.flags.busy ) - { - /* - * the disable function must not be called while there are - * requests pending for completion ! - */ - ret = -EBUSY; - } - else - { - /* - * If device isn't operational we have to perform delayed - * disabling when the next interrupt occurs - unless the - * irq is re-requested prior to the interrupt to occur. - */ - cc = stsch(irq, &(ioinfo[irq]->schib) ); - - if ( cc == 3 ) - { - ioinfo[irq]->ui.flags.oper = 0; - ioinfo[irq]->ui.flags.d_disable = 1; - - ret = 0; - } - else // cc == 0 - { - ioinfo[irq]->schib.pmcw.ena = 0; - - do - { - cc = msch( irq, &(ioinfo[irq]->schib) ); - - switch (cc) { - case 0 : - ret = 0; /* done */ - break; - - case 1 : - /* - * very bad, requires interrupt alike - * processing, where "rbh" is a dummy - * parm for interface compatibility - * only. Bottom-half handling cannot - * be required as this must be an - * unsolicited interrupt (!busy). - */ - ioinfo[irq]->ui.flags.s_pend = 1; - s390_process_IRQ( irq ); - ioinfo[irq]->ui.flags.s_pend = 0; - - ret = -EBUSY; /* might be overwritten */ - /* ... on re-driving the */ - /* ... msch() call */ - retry--; - break; - - case 2 : - /* - * *** must not occur ! *** - * *** *** - * *** indicates our internal *** - * *** interrupt accounting is out *** - * *** of sync ===> panic() *** - */ - printk( KERN_CRIT"disable_subchannel(%04X) " - "- unexpected busy condition for " - "device %04X received !\n", - irq, - ioinfo[irq]->devstat.devno); - - ret = -ENODEV; // never reached - break; - - case 3 : - /* - * should hardly occur ?! - */ - ioinfo[irq]->ui.flags.oper = 0; - ioinfo[irq]->ui.flags.d_disable = 1; - - ret = 0; /* if the device has gone we */ - /* ... don't need to disable */ - /* ... it anymore ! */ - break; - - default : - ret = -ENODEV; // never reached ... - break; - - } /* endswitch */ - - } while ( (cc == 1) && retry ); - - } /* endif */ - - } /* endif */ - - return( ret); -} - - - -int s390_setup_irq( unsigned int irq, struct irqaction * new) -{ - unsigned long flags; - int rc = 0; - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - /* - * The following block of code has to be executed atomically - */ - s390irq_spin_lock_irqsave( irq, flags); - - if ( ioinfo[irq]->irq_desc.action == NULL ) - { - ioinfo[irq]->irq_desc.action = new; - ioinfo[irq]->irq_desc.status = 0; - ioinfo[irq]->irq_desc.handler->enable = &enable_subchannel; - ioinfo[irq]->irq_desc.handler->disable = &disable_subchannel; - ioinfo[irq]->irq_desc.handler->handle = &handle_IRQ_event; - - ioinfo[irq]->ui.flags.ready = 1; - - ioinfo[irq]->irq_desc.handler->enable(irq); - } - else - { - /* - * interrupt already owned, and shared interrupts - * aren't supported on S/390. - */ - rc = -EBUSY; - - } /* endif */ - - s390irq_spin_unlock_irqrestore(irq,flags); - - return( rc); -} - -void s390_init_IRQ( void ) -{ - unsigned long flags; /* PSW flags */ - long cr6 __attribute__ ((aligned (8))); - - // Hopefully bh_count's will get set when we copy the prefix lowcore - // structure to other CPI's ( DJB ) - softirq_active(smp_processor_id()) = 0; - softirq_mask(smp_processor_id()) = 0; - local_bh_count(smp_processor_id()) = 0; - local_irq_count(smp_processor_id()) = 0; - syscall_count(smp_processor_id()) = 0; - - asm volatile ("STCK %0" : "=m" (irq_IPL_TOD)); - - /* - * As we don't know about the calling environment - * we assure running disabled. Before leaving the - * function we resestablish the old environment. - * - * Note : as we don't need a system wide lock, therefore - * we shouldn't use cli(), but __cli() as this - * affects the current CPU only. - */ - __save_flags(flags); - __cli(); - - /* - * disable all interrupts - */ - cr6 = 0; - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - s390_process_subchannels(); - - /* - * enable default I/O-interrupt sublass 3 - */ - cr6 = 0x10000000; - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - s390_device_recognition(); - - init_IRQ_complete = 1; - - s390_init_machine_check(); - - __restore_flags(flags); - - return; -} - - -/* - * dummy handler, used during init_IRQ() processing for compatibility only - */ -void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs) -{ - /* this is a dummy handler only ... */ -} - - -int s390_start_IO( int irq, /* IRQ */ - ccw1_t *cpa, /* logical channel prog addr */ - unsigned long user_intparm, /* interruption parameter */ - __u8 lpm, /* logical path mask */ - unsigned long flag) /* flags */ -{ - int ccode; - unsigned long psw_flags; - - int sync_isc_locked = 0; - int ret = 0; - - /* - * The flag usage is mutal exclusive ... - */ - if ( (flag & DOIO_RETURN_CHAN_END) - && (flag & DOIO_REPORT_ALL ) ) - { - return( -EINVAL ); - - } /* endif */ - - memset( &(ioinfo[irq]->orb), '\0', sizeof( orb_t) ); - - /* - * setup ORB - */ - ioinfo[irq]->orb.intparm = (__u32)&ioinfo[irq]->u_intparm; - ioinfo[irq]->orb.fmt = 1; - - ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH); - ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND); - ioinfo[irq]->orb.ssic = ( (flag & DOIO_ALLOW_SUSPEND ) - && (flag & DOIO_SUPPRESS_INTER) ); - - if ( flag & DOIO_VALID_LPM ) - { - ioinfo[irq]->orb.lpm = lpm; - } - else - { - ioinfo[irq]->orb.lpm = ioinfo[irq]->opm; - - } /* endif */ - - ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa); - - /* - * If sync processing was requested we lock the sync ISC, modify the - * device to present interrupts for this ISC only and switch the - * CPU to handle this ISC + the console ISC exclusively. - */ - if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { - // - // check whether we run recursively (sense processing) - // - if ( !ioinfo[irq]->ui.flags.syncio ) - { - spin_lock_irqsave( &sync_isc, psw_flags); - - ret = enable_cpu_sync_isc( irq); - - if ( ret ) - { - spin_unlock_irqrestore( &sync_isc, psw_flags); - return( ret); - } - else - { - sync_isc_locked = 1; // local - ioinfo[irq]->ui.flags.syncio = 1; // global - - } /* endif */ - - } /* endif */ - - } /* endif */ - - /* - * Issue "Start subchannel" and process condition code - */ - ccode = ssch( irq, &(ioinfo[irq]->orb) ); - - switch ( ccode ) { - case 0: - - if ( !ioinfo[irq]->ui.flags.w4sense ) - { - /* - * init the device driver specific devstat irb area - * - * Note : don´t clear saved irb info in case of sense ! - */ - memset( &((devstat_t *)ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, - '\0', sizeof( irb_t) ); - } /* endif */ - - /* - * initialize device status information - */ - ioinfo[irq]->ui.flags.busy = 1; - ioinfo[irq]->ui.flags.doio = 1; - - ioinfo[irq]->u_intparm = user_intparm; - ioinfo[irq]->devstat.cstat = 0; - ioinfo[irq]->devstat.dstat = 0; - ioinfo[irq]->devstat.lpum = 0; - ioinfo[irq]->devstat.flag = DEVSTAT_START_FUNCTION; - ioinfo[irq]->devstat.scnt = 0; - - ioinfo[irq]->ui.flags.fast = 0; - ioinfo[irq]->ui.flags.repall = 0; - - /* - * Check for either early (FAST) notification requests - * or if we are to return all interrupt info. - * Default is to call IRQ handler at secondary status only - */ - if ( flag & DOIO_RETURN_CHAN_END ) - { - ioinfo[irq]->ui.flags.fast = 1; - } - else if ( flag & DOIO_REPORT_ALL ) - { - ioinfo[irq]->ui.flags.repall = 1; - - } /* endif */ - - ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm; - - /* - * If synchronous I/O processing is requested, we have - * to wait for the corresponding interrupt to occur by - * polling the interrupt condition. However, as multiple - * interrupts may be outstanding, we must not just wait - * for the first interrupt, but must poll until ours - * pops up. - */ - if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { - // __u32 io_parm; - psw_t io_new_psw; - int ccode; - - int ready = 0; - int io_sub = -1; - struct _lowcore *lc = NULL; - int count = 30000; - - /* - * We shouldn't perform a TPI loop, waiting for an - * interrupt to occur, but should load a WAIT PSW - * instead. Otherwise we may keep the channel subsystem - * busy, not able to present the interrupt. When our - * sync. interrupt arrived we reset the I/O old PSW to - * its original value. - */ - memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t)); - - ccode = iac(); - - switch (ccode) { - case 0: // primary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_PRIM_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 1: // secondary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_SEC_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 2: // access-register - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_ACC_REG_MODE - | _PSW_IO_WAIT; - break; - case 3: // home-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_HOME_SPACE_MODE - | _PSW_IO_WAIT; - break; - default: - panic( "start_IO() : unexpected " - "address-space-control %d\n", - ccode); - break; - } /* endswitch */ - - io_sync_wait.addr = FIX_PSW(&&io_wakeup); - - /* - * Martin didn't like modifying the new PSW, now we take - * a fast exit in do_IRQ() instead - */ - *(__u32 *)__LC_SYNC_IO_WORD = 1; - - do - { - if ( flag & DOIO_TIMEOUT ) - { - tpi_info_t tpi_info; - - do - { - if ( tpi(&tpi_info) == 1 ) - { - io_sub = tpi_info.irq; - break; - } - else - { - count--; - tod_wait(100); /* usecs */ - - } /* endif */ - - } while ( count ); - } - else - { - asm volatile ("lpsw %0" : : "m" (io_sync_wait)); - -io_wakeup: - io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; - - } /* endif */ - - if ( count ) - ready = s390_process_IRQ( io_sub ); - - /* - * surrender when retry count's exceeded ... - */ - - } while ( !( ( io_sub == irq ) - && ( ready == 1 )) - && count ); - - *(__u32 *)__LC_SYNC_IO_WORD = 0; - - if ( !count ) - ret = -ETIMEDOUT; - - } /* endif */ - - break; - - case 1 : /* status pending */ - - ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING; - - /* - * initialize the device driver specific devstat irb area - */ - memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, - '\0', sizeof( irb_t) ); - - /* - * Let the common interrupt handler process the pending status. - * However, we must avoid calling the user action handler, as - * it won't be prepared to handle a pending status during - * do_IO() processing inline. This also implies that process_IRQ - * must terminate synchronously - especially if device sensing - * is required. - */ - ioinfo[irq]->ui.flags.s_pend = 1; - ioinfo[irq]->ui.flags.busy = 1; - ioinfo[irq]->ui.flags.doio = 1; - - s390_process_IRQ( irq ); - - ioinfo[irq]->ui.flags.s_pend = 0; - ioinfo[irq]->ui.flags.busy = 0; - ioinfo[irq]->ui.flags.doio = 0; - ioinfo[irq]->ui.flags.repall = 0; - ioinfo[irq]->ui.flags.w4final = 0; - - ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS; - - /* - * In multipath mode a condition code 3 implies the last path - * has gone, except we have previously restricted the I/O to - * a particular path. A condition code 1 (0 won't occur) - * results in return code EIO as well as 3 with another path - * than the one used (i.e. path available mask is non-zero). - */ - if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 ) - { - ret = -ENODEV; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - ioinfo[irq]->ui.flags.oper = 0; - -#if CONFIG_DEBUG_IO - { - char buffer[80]; - - stsch(irq, &(ioinfo[irq]->schib) ); - - sprintf( buffer, "s390_start_IO(%04X) - irb for " - "device %04X, after status pending\n", - irq, - ioinfo[irq]->devstat.devno ); - - s390_displayhex( buffer, - &(ioinfo[irq]->devstat.ii.irb) , - sizeof(irb_t)); - - sprintf( buffer, "s390_start_IO(%04X) - schib for " - "device %04X, after status pending\n", - irq, - ioinfo[irq]->devstat.devno ); - - s390_displayhex( buffer, - &(ioinfo[irq]->schib) , - sizeof(schib_t)); - - - if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL) - { - sprintf( buffer, "s390_start_IO(%04X) - sense " - "data for " - "device %04X, after status pending\n", - irq, - ioinfo[irq]->devstat.devno ); - - s390_displayhex( buffer, - ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->ii.sense.data, - ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt); - - } - } -#endif - } - else - { - ret = -EIO; - ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER; - ioinfo[irq]->ui.flags.oper = 1; - - } /* endif */ - - break; - - case 2 : /* busy */ - - ret = -EBUSY; - break; - - default: /* device not operational */ - - ret = -ENODEV; - ioinfo[irq]->ui.flags.oper = 0; - - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - - memcpy( ioinfo[irq]->irq_desc.action->dev_id, - &(ioinfo[irq]->devstat), - sizeof( devstat_t) ); - -#if CONFIG_DEBUG_IO - { - char buffer[80]; - - stsch(irq, &(ioinfo[irq]->schib) ); - - sprintf( buffer, "s390_start_IO(%04X) - schib for " - "device %04X, after 'not oper' status\n", - irq, - ioinfo[irq]->devstat.devno ); - - s390_displayhex( buffer, - &(ioinfo[irq]->schib), - sizeof(schib_t)); - } -#endif - break; - - } /* endswitch */ - - if ( ( flag & DOIO_WAIT_FOR_INTERRUPT ) - && ( sync_isc_locked ) ) - { - disable_cpu_sync_isc( irq ); - - spin_unlock_irqrestore( &sync_isc, psw_flags); - - sync_isc_locked = 0; // local setting - ioinfo[irq]->ui.flags.syncio = 0; // global setting - - } /* endif */ - - return( ret); -} - -int do_IO( int irq, /* IRQ */ - ccw1_t *cpa, /* channel program address */ - unsigned long user_intparm, /* interruption parameter */ - __u8 lpm, /* logical path mask */ - unsigned long flag) /* flags : see above */ -{ - int ret = 0; - - if ( irq > highest_subchannel || irq < 0 ) - { - return( -ENODEV ); - - } /* endif */ - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - /* handler registered ? or free_irq() in process already ? */ - if ( !ioinfo[irq]->ui.flags.ready || ioinfo[irq]->ui.flags.unready ) - { - return( -ENODEV ); - - } /* endif */ - - /* - * Note: We ignore the device operational status - if not operational, - * the SSCH will lead to an -ENODEV condition ... - */ - if ( !ioinfo[irq]->ui.flags.busy ) /* last I/O completed ? */ - { - ret = s390_start_IO( irq, cpa, user_intparm, lpm, flag); - } - else if ( ioinfo[irq]->ui.flags.fast ) - { - /* - * If primary status was received and ending status is missing, - * the device driver won't be notified on the ending status - * if early (fast) interrupt notification was requested. - * Therefore we have to queue the next incoming request. If - * halt_IO() is issued while there is a request queued, a HSCH - * needs to be issued and the queued request must be deleted - * but its intparm must be returned (see halt_IO() processing) - */ - if ( ioinfo[irq]->ui.flags.w4final - && !ioinfo[irq]->ui.flags.doio_q ) - { - ioinfo[irq]->qflag = flag; - ioinfo[irq]->qcpa = cpa; - ioinfo[irq]->qintparm = user_intparm; - ioinfo[irq]->qlpm = lpm; - } - else - { - ret = -EBUSY; - - } /* endif */ - } - else - { - ret = -EBUSY; - - } /* endif */ - - return( ret ); - -} - -/* - * resume suspended I/O operation - */ -int resume_IO( int irq) -{ - int ret = 0; - - if ( irq > highest_subchannel || irq < 0 ) - { - return( -ENODEV ); - - } /* endif */ - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - /* - * We allow for 'resume' requests only for active I/O operations - */ - if ( ioinfo[irq]->ui.flags.busy ) - { - int ccode; - - ccode = rsch( irq); - - switch (ccode) { - case 0 : - break; - - case 1 : - s390_process_IRQ( irq ); - ret = -EBUSY; - break; - - case 2 : - ret = -EINVAL; - break; - - case 3 : - /* - * useless to wait for request completion - * as device is no longer operational ! - */ - ioinfo[irq]->ui.flags.oper = 0; - ioinfo[irq]->ui.flags.busy = 0; - ret = -ENODEV; - break; - - } /* endswitch */ - - } - else - { - ret = -ENOTCONN; - - } /* endif */ - - return( ret); -} - -/* - * Note: The "intparm" parameter is not used by the halt_IO() function - * itself, as no ORB is built for the HSCH instruction. However, - * it allows the device interrupt handler to associate the upcoming - * interrupt with the halt_IO() request. - */ -int halt_IO( int irq, - unsigned long user_intparm, - unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */ -{ - int ret; - int ccode; - unsigned long psw_flags; - - int sync_isc_locked = 0; - - if ( irq > highest_subchannel || irq < 0 ) - { - ret = -ENODEV; - } - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - /* - * we only allow for halt_IO if the device has an I/O handler associated - */ - else if ( !ioinfo[irq]->ui.flags.ready ) - { - ret = -ENODEV; - } - /* - * we ignore the halt_io() request if ending_status was received but - * a SENSE operation is waiting for completion. - */ - else if ( ioinfo[irq]->ui.flags.w4sense ) - { - ret = 0; - } - /* - * We don't allow for halt_io with a sync do_IO() requests pending. - */ - else if ( ioinfo[irq]->ui.flags.syncio ) - { - ret = -EBUSY; - } - else - { - /* - * If sync processing was requested we lock the sync ISC, - * modify the device to present interrupts for this ISC only - * and switch the CPU to handle this ISC + the console ISC - * exclusively. - */ - if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { - // - // check whether we run recursively (sense processing) - // - if ( !ioinfo[irq]->ui.flags.syncio ) - { - spin_lock_irqsave( &sync_isc, psw_flags); - - ret = enable_cpu_sync_isc( irq); - - if ( ret ) - { - spin_unlock_irqrestore( &sync_isc, - psw_flags); - return( ret); - } - else - { - sync_isc_locked = 1; // local - ioinfo[irq]->ui.flags.syncio = 1; // global - - } /* endif */ - - } /* endif */ - - } /* endif */ - - /* - * Issue "Halt subchannel" and process condition code - */ - ccode = hsch( irq ); - - switch ( ccode ) { - case 0: - - ioinfo[irq]->ui.flags.haltio = 1; - - if ( !ioinfo[irq]->ui.flags.doio ) - { - ioinfo[irq]->ui.flags.busy = 1; - ioinfo[irq]->u_intparm = user_intparm; - ioinfo[irq]->devstat.cstat = 0; - ioinfo[irq]->devstat.dstat = 0; - ioinfo[irq]->devstat.lpum = 0; - ioinfo[irq]->devstat.flag = DEVSTAT_HALT_FUNCTION; - ioinfo[irq]->devstat.scnt = 0; - - } - else - { - ioinfo[irq]->devstat.flag |= DEVSTAT_HALT_FUNCTION; - - } /* endif */ - - /* - * If synchronous I/O processing is requested, we have - * to wait for the corresponding interrupt to occur by - * polling the interrupt condition. However, as multiple - * interrupts may be outstanding, we must not just wait - * for the first interrupt, but must poll until ours - * pops up. - */ - if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { - int io_sub; - __u32 io_parm; - psw_t io_new_psw; - int ccode; - - int ready = 0; - struct _lowcore *lc = NULL; - - /* - * We shouldn't perform a TPI loop, waiting for - * an interrupt to occur, but should load a - * WAIT PSW instead. Otherwise we may keep the - * channel subsystem busy, not able to present - * the interrupt. When our sync. interrupt - * arrived we reset the I/O old PSW to its - * original value. - */ - memcpy( &io_new_psw, - &lc->io_new_psw, - sizeof(psw_t)); - - ccode = iac(); - - switch (ccode) { - case 0: // primary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_PRIM_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 1: // secondary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_SEC_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 2: // access-register - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_ACC_REG_MODE - | _PSW_IO_WAIT; - break; - case 3: // home-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_HOME_SPACE_MODE - | _PSW_IO_WAIT; - break; - default: - panic( "halt_IO() : unexpected " - "address-space-control %d\n", - ccode); - break; - } /* endswitch */ - - io_sync_wait.addr = FIX_PSW(&&hio_wakeup); - - /* - * Martin didn't like modifying the new PSW, now we take - * a fast exit in do_IRQ() instead - */ - *(__u32 *)__LC_SYNC_IO_WORD = 1; - - do - { - - asm volatile ( "lpsw %0" : : "m" (io_sync_wait) ); -hio_wakeup: - io_parm = *(__u32 *)__LC_IO_INT_PARM; - io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; - - ready = s390_process_IRQ( io_sub ); - - } while ( !((io_sub == irq) && (ready == 1)) ); - - *(__u32 *)__LC_SYNC_IO_WORD = 0; - - } /* endif */ - - ret = 0; - break; - - case 1 : /* status pending */ - - ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING; - - /* - * initialize the device driver specific devstat irb area - */ - memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, - '\0', sizeof( irb_t) ); - - /* - * Let the common interrupt handler process the pending - * status. However, we must avoid calling the user - * action handler, as it won't be prepared to handle - * a pending status during do_IO() processing inline. - * This also implies that s390_process_IRQ must - * terminate synchronously - especially if device - * sensing is required. - */ - ioinfo[irq]->ui.flags.s_pend = 1; - ioinfo[irq]->ui.flags.busy = 1; - ioinfo[irq]->ui.flags.doio = 1; - - s390_process_IRQ( irq ); - - ioinfo[irq]->ui.flags.s_pend = 0; - ioinfo[irq]->ui.flags.busy = 0; - ioinfo[irq]->ui.flags.doio = 0; - ioinfo[irq]->ui.flags.repall = 0; - ioinfo[irq]->ui.flags.w4final = 0; - - ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS; - - /* - * In multipath mode a condition code 3 implies the last - * path has gone, except we have previously restricted - * the I/O to a particular path. A condition code 1 - * (0 won't occur) results in return code EIO as well - * as 3 with another path than the one used (i.e. path available mask is non-zero). - */ - if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 ) - { - ret = -ENODEV; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - ioinfo[irq]->ui.flags.oper = 0; - } - else - { - ret = -EIO; - ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER; - ioinfo[irq]->ui.flags.oper = 1; - - } /* endif */ - - break; - - case 2 : /* busy */ - - ret = -EBUSY; - break; - - default: /* device not operational */ - - ret = -ENODEV; - break; - - } /* endswitch */ - - if ( ( flag & DOIO_WAIT_FOR_INTERRUPT ) - && ( sync_isc_locked ) ) - { - sync_isc_locked = 0; // local setting - ioinfo[irq]->ui.flags.syncio = 0; // global setting - - disable_cpu_sync_isc( irq ); - - spin_unlock_irqrestore( &sync_isc, psw_flags); - - } /* endif */ - - } /* endif */ - - return( ret ); -} - -/* - * Note: The "intparm" parameter is not used by the clear_IO() function - * itself, as no ORB is built for the CSCH instruction. However, - * it allows the device interrupt handler to associate the upcoming - * interrupt with the clear_IO() request. - */ -int clear_IO( int irq, - unsigned long user_intparm, - unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */ -{ - int ret; - int ccode; - unsigned long psw_flags; - - int sync_isc_locked = 0; - - if ( irq > highest_subchannel || irq < 0 ) - { - ret = -ENODEV; - } - - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - /* - * we only allow for halt_IO if the device has an I/O handler associated - */ - else if ( !ioinfo[irq]->ui.flags.ready ) - { - ret = -ENODEV; - } - /* - * we ignore the halt_io() request if ending_status was received but - * a SENSE operation is waiting for completion. - */ - else if ( ioinfo[irq]->ui.flags.w4sense ) - { - ret = 0; - } - /* - * We don't allow for halt_io with a sync do_IO() requests pending. - * Concurrent I/O is possible in SMP environments only, but the - * sync. I/O request can be gated to one CPU at a time only. - */ - else if ( ioinfo[irq]->ui.flags.syncio ) - { - ret = -EBUSY; - } - else - { - /* - * If sync processing was requested we lock the sync ISC, - * modify the device to present interrupts for this ISC only - * and switch the CPU to handle this ISC + the console ISC - * exclusively. - */ - if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { - // - // check whether we run recursively (sense processing) - // - if ( !ioinfo[irq]->ui.flags.syncio ) - { - spin_lock_irqsave( &sync_isc, psw_flags); - - ret = enable_cpu_sync_isc( irq); - - if ( ret ) - { - spin_unlock_irqrestore( &sync_isc, - psw_flags); - return( ret); - } - else - { - sync_isc_locked = 1; // local - ioinfo[irq]->ui.flags.syncio = 1; // global - - } /* endif */ - - } /* endif */ - - } /* endif */ - - /* - * Issue "Halt subchannel" and process condition code - */ - ccode = csch( irq ); - - switch ( ccode ) { - case 0: - - ioinfo[irq]->ui.flags.haltio = 1; - - if ( !ioinfo[irq]->ui.flags.doio ) - { - ioinfo[irq]->ui.flags.busy = 1; - ioinfo[irq]->u_intparm = user_intparm; - ioinfo[irq]->devstat.cstat = 0; - ioinfo[irq]->devstat.dstat = 0; - ioinfo[irq]->devstat.lpum = 0; - ioinfo[irq]->devstat.flag = DEVSTAT_CLEAR_FUNCTION; - ioinfo[irq]->devstat.scnt = 0; - - } - else - { - ioinfo[irq]->devstat.flag |= DEVSTAT_CLEAR_FUNCTION; - - } /* endif */ - - /* - * If synchronous I/O processing is requested, we have - * to wait for the corresponding interrupt to occur by - * polling the interrupt condition. However, as multiple - * interrupts may be outstanding, we must not just wait - * for the first interrupt, but must poll until ours - * pops up. - */ - if ( flag & DOIO_WAIT_FOR_INTERRUPT ) - { - int io_sub; - __u32 io_parm; - psw_t io_new_psw; - int ccode; - - int ready = 0; - struct _lowcore *lc = NULL; - - /* - * We shouldn't perform a TPI loop, waiting for - * an interrupt to occur, but should load a - * WAIT PSW instead. Otherwise we may keep the - * channel subsystem busy, not able to present - * the interrupt. When our sync. interrupt - * arrived we reset the I/O old PSW to its - * original value. - */ - memcpy( &io_new_psw, - &lc->io_new_psw, - sizeof(psw_t)); - - ccode = iac(); - - switch (ccode) { - case 0: // primary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_PRIM_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 1: // secondary-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_SEC_SPACE_MODE - | _PSW_IO_WAIT; - break; - case 2: // access-register - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_ACC_REG_MODE - | _PSW_IO_WAIT; - break; - case 3: // home-space - io_sync_wait.mask = _IO_PSW_MASK - | _PSW_HOME_SPACE_MODE - | _PSW_IO_WAIT; - break; - default: - panic( "halt_IO() : unexpected " - "address-space-control %d\n", - ccode); - break; - } /* endswitch */ - - io_sync_wait.addr = FIX_PSW(&&cio_wakeup); - - /* - * Martin didn't like modifying the new PSW, now we take - * a fast exit in do_IRQ() instead - */ - *(__u32 *)__LC_SYNC_IO_WORD = 1; - - do - { - - asm volatile ( "lpsw %0" : : "m" (io_sync_wait) ); -cio_wakeup: - io_parm = *(__u32 *)__LC_IO_INT_PARM; - io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR; - - ready = s390_process_IRQ( io_sub ); - - } while ( !((io_sub == irq) && (ready == 1)) ); - - *(__u32 *)__LC_SYNC_IO_WORD = 0; - - } /* endif */ - - ret = 0; - break; - - case 1 : /* status pending */ - - ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING; - - /* - * initialize the device driver specific devstat irb area - */ - memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb, - '\0', sizeof( irb_t) ); - - /* - * Let the common interrupt handler process the pending - * status. However, we must avoid calling the user - * action handler, as it won't be prepared to handle - * a pending status during do_IO() processing inline. - * This also implies that s390_process_IRQ must - * terminate synchronously - especially if device - * sensing is required. - */ - ioinfo[irq]->ui.flags.s_pend = 1; - ioinfo[irq]->ui.flags.busy = 1; - ioinfo[irq]->ui.flags.doio = 1; - - s390_process_IRQ( irq ); - - ioinfo[irq]->ui.flags.s_pend = 0; - ioinfo[irq]->ui.flags.busy = 0; - ioinfo[irq]->ui.flags.doio = 0; - ioinfo[irq]->ui.flags.repall = 0; - ioinfo[irq]->ui.flags.w4final = 0; - - ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS; - - /* - * In multipath mode a condition code 3 implies the last - * path has gone, except we have previously restricted - * the I/O to a particular path. A condition code 1 - * (0 won't occur) results in return code EIO as well - * as 3 with another path than the one used (i.e. path available mask is non-zero). - */ - if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 ) - { - ret = -ENODEV; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - ioinfo[irq]->ui.flags.oper = 0; - } - else - { - ret = -EIO; - ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER; - ioinfo[irq]->ui.flags.oper = 1; - - } /* endif */ - - break; - - case 2 : /* busy */ - - ret = -EBUSY; - break; - - default: /* device not operational */ - - ret = -ENODEV; - break; - - } /* endswitch */ - - if ( ( flag & DOIO_WAIT_FOR_INTERRUPT ) - && ( sync_isc_locked ) ) - { - sync_isc_locked = 0; // local setting - ioinfo[irq]->ui.flags.syncio = 0; // global setting - - disable_cpu_sync_isc( irq ); - - spin_unlock_irqrestore( &sync_isc, psw_flags); - - } /* endif */ - - } /* endif */ - - return( ret ); -} - - -/* - * do_IRQ() handles all normal I/O device IRQ's (the special - * SMP cross-CPU interrupts have their own specific - * handlers). - * - * Returns: 0 - no ending status received, no further action taken - * 1 - interrupt handler was called with ending status - */ -asmlinkage void do_IRQ( struct pt_regs regs, - unsigned int irq, - __u32 s390_intparm ) -{ -#ifdef CONFIG_FAST_IRQ - int ccode; - tpi_info_t tpi_info; - int new_irq; -#endif - int use_irq = irq; -// __u32 use_intparm = s390_intparm; - - // - // fix me !!! - // - // We need to schedule device recognition, the interrupt stays - // pending. We need to dynamically allocate an ioinfo structure. - // - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return; /* this keeps the device boxed ... */ - } - - /* - * take fast exit if CPU is in sync. I/O state - * - * Note: we have to turn off the WAIT bit and re-disable - * interrupts prior to return as this was the initial - * entry condition to synchronous I/O. - */ - if ( *(__u32 *)__LC_SYNC_IO_WORD ) - { - regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT); - - return; - - } /* endif */ - - s390irq_spin_lock(use_irq); - -#ifdef CONFIG_FAST_IRQ - do { -#endif /* CONFIG_FAST_IRQ */ - - s390_process_IRQ( use_irq ); - -#ifdef CONFIG_FAST_IRQ - - /* - * more interrupts pending ? - */ - ccode = tpi( &tpi_info ); - - if ( ! ccode ) - break; // no, leave ... - - new_irq = tpi_info.irq; -// use_intparm = tpi_info.intparm; - - /* - * if the interrupt is for a different irq we - * release the current irq lock and obtain - * a new one ... - */ - if ( new_irq != use_irq ) - { - s390irq_spin_unlock(use_irq); - use_irq = new_irq; - s390irq_spin_lock(use_irq); - - } /* endif */ - - } while ( 1 ); - -#endif /* CONFIG_FAST_IRQ */ - - s390irq_spin_unlock(use_irq); - - return; -} - -/* - * s390_process_IRQ() handles status pending situations and interrupts - * - * Called by : do_IRQ() - for "real" interrupts - * s390_start_IO, halt_IO() - * - status pending cond. after SSCH, or HSCH - * disable_subchannel() - status pending conditions (after MSCH) - * - * Returns: 0 - no ending status received, no further action taken - * 1 - interrupt handler was called with ending status - */ -int s390_process_IRQ( unsigned int irq ) -{ - int ccode; /* condition code from tsch() operation */ - int irb_cc; /* condition code from irb */ - int sdevstat; /* effective struct devstat size to copy */ - unsigned int fctl; /* function control */ - unsigned int stctl; /* status control */ - unsigned int actl; /* activity control */ - struct irqaction *action; - struct pt_regs regs; /* for interface compatibility only */ - - int issense = 0; - int ending_status = 0; - int allow4handler = 1; - int chnchk = 0; -#if 0 - int cpu = smp_processor_id(); - - kstat.irqs[cpu][irq]++; -#endif - action = ioinfo[irq]->irq_desc.action; - - /* - * It might be possible that a device was not-oper. at the time - * of free_irq() processing. This means the handler is no longer - * available when the device possibly becomes ready again. In - * this case we perform delayed disable_subchannel() processing. - */ - if ( action == NULL ) - { - if ( !ioinfo[irq]->ui.flags.d_disable ) - { - printk( KERN_CRIT"s390_process_IRQ(%04X) " - "- no interrupt handler registered" - "for device %04X !\n", - irq, - ioinfo[irq]->devstat.devno); - - } /* endif */ - - } /* endif */ - - /* - * retrieve the i/o interrupt information (irb), - * update the device specific status information - * and possibly call the interrupt handler. - * - * Note 1: At this time we don't process the resulting - * condition code (ccode) from tsch(), although - * we probably should. - * - * Note 2: Here we will have to check for channel - * check conditions and call a channel check - * handler. - * - * Note 3: If a start function was issued, the interruption - * parameter relates to it. If a halt function was - * issued for an idle device, the intparm must not - * be taken from lowcore, but from the devstat area. - */ - ccode = tsch( irq, &(ioinfo[irq]->devstat.ii.irb) ); - - // - // We must only accumulate the status if initiated by do_IO() or halt_IO() - // - if ( ioinfo[irq]->ui.flags.busy ) - { - ioinfo[irq]->devstat.dstat |= ioinfo[irq]->devstat.ii.irb.scsw.dstat; - ioinfo[irq]->devstat.cstat |= ioinfo[irq]->devstat.ii.irb.scsw.cstat; - } - else - { - ioinfo[irq]->devstat.dstat = ioinfo[irq]->devstat.ii.irb.scsw.dstat; - ioinfo[irq]->devstat.cstat = ioinfo[irq]->devstat.ii.irb.scsw.cstat; - - ioinfo[irq]->devstat.flag = 0; // reset status flags - - } /* endif */ - - ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum; - - if ( ioinfo[irq]->ui.flags.busy) - { - ioinfo[irq]->devstat.intparm = ioinfo[irq]->u_intparm; - - } /* endif */ - - /* - * reset device-busy bit if no longer set in irb - */ - if ( (ioinfo[irq]->devstat.dstat & DEV_STAT_BUSY ) - && ((ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0)) - { - ioinfo[irq]->devstat.dstat &= ~DEV_STAT_BUSY; - - } /* endif */ - - /* - * Save residual count and CCW information in case primary and - * secondary status are presented with different interrupts. - */ - if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl & SCSW_STCTL_PRIM_STATUS ) - { - ioinfo[irq]->devstat.rescnt = ioinfo[irq]->devstat.ii.irb.scsw.count; - -#if CONFIG_DEBUG_IO - if ( irq != cons_dev ) - printk( "s390_process_IRQ( %04X ) : " - "residual count from irb after tsch() %d\n", - irq, ioinfo[irq]->devstat.rescnt ); -#endif - } /* endif */ - - if ( ioinfo[irq]->devstat.ii.irb.scsw.cpa != 0 ) - { - ioinfo[irq]->devstat.cpa = ioinfo[irq]->devstat.ii.irb.scsw.cpa; - - } /* endif */ - - irb_cc = ioinfo[irq]->devstat.ii.irb.scsw.cc; - - // - // check for any kind of channel or interface control check but don't - // issue the message for the console device - // - if ( (ioinfo[irq]->devstat.ii.irb.scsw.cstat - & ( SCHN_STAT_CHN_DATA_CHK - | SCHN_STAT_CHN_CTRL_CHK - | SCHN_STAT_INTF_CTRL_CHK ) ) - && (irq != cons_dev ) ) - { - printk( "Channel-Check or Interface-Control-Check " - "received\n" - " ... device %04X on subchannel %04X, dev_stat " - ": %02X sch_stat : %02X\n", - ioinfo[irq]->devstat.devno, - irq, - ioinfo[irq]->devstat.dstat, - ioinfo[irq]->devstat.cstat); - - chnchk = 1; - - } /* endif */ - - issense = ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.cons; - - if ( issense ) - { - ioinfo[irq]->devstat.scnt = - ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.scnt; - ioinfo[irq]->devstat.flag |= - DEVSTAT_FLAG_SENSE_AVAIL; - - sdevstat = sizeof( devstat_t); - -#if CONFIG_DEBUG_IO - if ( irq != cons_dev ) - printk( "s390_process_IRQ( %04X ) : " - "concurrent sense bytes avail %d\n", - irq, ioinfo[irq]->devstat.scnt ); -#endif - } - else - { - /* don't copy the sense data area ! */ - sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT; - - } /* endif */ - - switch ( irb_cc ) { - case 1: /* status pending */ - - ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING; - - case 0: /* normal i/o interruption */ - - fctl = ioinfo[irq]->devstat.ii.irb.scsw.fctl; - stctl = ioinfo[irq]->devstat.ii.irb.scsw.stctl; - actl = ioinfo[irq]->devstat.ii.irb.scsw.actl; - - if ( chnchk && (ioinfo[irq]->senseid.cu_type == 0x3088)) - { - char buffer[80]; - - sprintf( buffer, "s390_process_IRQ(%04X) - irb for " - "device %04X after channel check\n", - irq, - ioinfo[irq]->devstat.devno ); - - s390_displayhex( buffer, - &(ioinfo[irq]->devstat.ii.irb) , - sizeof(irb_t)); - } /* endif */ - - ioinfo[irq]->stctl |= stctl; - - ending_status = ( stctl & SCSW_STCTL_SEC_STATUS ) - || ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND) ) - || ( (fctl == SCSW_FCTL_HALT_FUNC) && (stctl == SCSW_STCTL_STATUS_PEND) ); - - /* - * Check for unsolicited interrupts - for debug purposes only - * - * We only consider an interrupt as unsolicited, if the device was not - * actively in use (busy) and an interrupt other than an ALERT status - * was received. - * - * Note: We must not issue a message to the console, if the - * unsolicited interrupt applies to the console device - * itself ! - */ -#if CONFIG_DEBUG_IO - if ( ( irq != cons_dev ) - && !( stctl & SCSW_STCTL_ALERT_STATUS ) - && ( ioinfo[irq]->ui.flags.busy == 0 ) ) - { - char buffer[80]; - - printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n" - " ... device status : %02X subchannel status : %02X\n", - ioinfo[irq]->devstat.devno, - irq, - ioinfo[irq]->devstat.dstat, - ioinfo[irq]->devstat.cstat); - - sprintf( buffer, "s390_process_IRQ(%04X) - irb for " - "device %04X, ending_status %d\n", - irq, - ioinfo[irq]->devstat.devno, - ending_status); - - s390_displayhex( buffer, - &(ioinfo[irq]->devstat.ii.irb) , - sizeof(irb_t)); - - } /* endif */ - - /* - * take fast exit if no handler is available - */ - if ( !action ) - return( ending_status ); - -#endif - /* - * Check whether we must issue a SENSE CCW ourselves if there is no - * concurrent sense facility installed for the subchannel. - * - * Note: We should check for ioinfo[irq]->ui.flags.consns but VM - * violates the ESA/390 architecture and doesn't present an - * operand exception for virtual devices without concurrent - * sense facility available/supported when enabling the - * concurrent sense facility. - */ - if ( ( ( ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_UNIT_CHECK ) - && ( !issense ) ) - || ( ioinfo[irq]->ui.flags.delsense && ending_status ) ) - { - int ret_io; - ccw1_t *s_ccw = &ioinfo[irq]->senseccw; - unsigned long s_flag = 0; - - if ( ending_status ) - { - /* - * We copy the current status information into the device driver - * status area. Then we can use the local devstat area for device - * sensing. When finally calling the IRQ handler we must not overlay - * the original device status but copy the sense data only. - */ - memcpy( action->dev_id, - &(ioinfo[irq]->devstat), - sizeof( devstat_t) ); - - s_ccw->cmd_code = CCW_CMD_BASIC_SENSE; - s_ccw->cda = (__u32)virt_to_phys( ioinfo[irq]->devstat.ii.sense.data); - s_ccw->count = SENSE_MAX_COUNT; - s_ccw->flags = CCW_FLAG_SLI; - - /* - * If free_irq() or a sync do_IO/s390_start_IO() is in - * process we have to sense synchronously - */ - if ( ioinfo[irq]->ui.flags.unready || ioinfo[irq]->ui.flags.syncio ) - { - s_flag = DOIO_WAIT_FOR_INTERRUPT; - - } /* endif */ - - /* - * Reset status info - * - * It does not matter whether this is a sync. or async. - * SENSE request, but we have to assure we don't call - * the irq handler now, but keep the irq in busy state. - * In sync. mode s390_process_IRQ() is called recursively, - * while in async. mode we re-enter do_IRQ() with the - * next interrupt. - * - * Note : this may be a delayed sense request ! - */ - allow4handler = 0; - - ioinfo[irq]->ui.flags.fast = 0; - ioinfo[irq]->ui.flags.repall = 0; - ioinfo[irq]->ui.flags.w4final = 0; - ioinfo[irq]->ui.flags.delsense = 0; - - ioinfo[irq]->devstat.cstat = 0; - ioinfo[irq]->devstat.dstat = 0; - ioinfo[irq]->devstat.rescnt = SENSE_MAX_COUNT; - - ioinfo[irq]->ui.flags.w4sense = 1; - - ret_io = s390_start_IO( irq, - s_ccw, - 0xE2C5D5E2, // = SENSe - 0, // n/a - s_flag); - } - else - { - /* - * we received an Unit Check but we have no final - * status yet, therefore we must delay the SENSE - * processing. However, we must not report this - * intermediate status to the device interrupt - * handler. - */ - ioinfo[irq]->ui.flags.fast = 0; - ioinfo[irq]->ui.flags.repall = 0; - - ioinfo[irq]->ui.flags.delsense = 1; - allow4handler = 0; - - } /* endif */ - - } /* endif */ - - /* - * we allow for the device action handler if . - * - we received ending status - * - the action handler requested to see all interrupts - * - we received a PCI - * - fast notification was requested (primary status) - * - unsollicited interrupts - * - */ - if ( allow4handler ) - { - allow4handler = ending_status - || ( ioinfo[irq]->ui.flags.repall ) - || ( ioinfo[irq]->devstat.ii.irb.scsw.cstat & SCHN_STAT_PCI ) - || ( (ioinfo[irq]->ui.flags.fast ) && (stctl & SCSW_STCTL_PRIM_STATUS) ) - || ( ioinfo[irq]->ui.flags.oper == 0 ); - - } /* endif */ - - /* - * We used to copy the device status information right before - * calling the device action handler. However, in status - * pending situations during do_IO() or halt_IO(), as well as - * enable_subchannel/disable_subchannel processing we must - * synchronously return the status information and must not - * call the device action handler. - * - */ - if ( allow4handler ) - { - /* - * if we were waiting for sense data we copy the sense - * bytes only as the original status information was - * saved prior to sense already. - */ - if ( ioinfo[irq]->ui.flags.w4sense ) - { - int sense_count = SENSE_MAX_COUNT-ioinfo[irq]->devstat.rescnt; - -#if CONFIG_DEBUG_IO - if ( irq != cons_dev ) - printk( "s390_process_IRQ( %04X ) : " - "BASIC SENSE bytes avail %d\n", - irq, sense_count ); -#endif - ioinfo[irq]->ui.flags.w4sense = 0; - ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FLAG_SENSE_AVAIL; - ((devstat_t *)(action->dev_id))->scnt = sense_count; - - if ( sense_count >= 0 ) - { - memcpy( ((devstat_t *)(action->dev_id))->ii.sense.data, - &(ioinfo[irq]->devstat.ii.sense.data), - sense_count); - } - else - { -#if 1 - panic( "s390_process_IRQ(%04x) encountered " - "negative sense count\n", - irq); -#else - printk( KERN_CRIT"s390_process_IRQ(%04x) encountered " - "negative sense count\n", - irq); -#endif - } /* endif */ - } - else - { - memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat ); - - } /* endif */ - - } /* endif */ - - /* - * for status pending situations other than deferred interrupt - * conditions detected by s390_process_IRQ() itself we must not - * call the handler. This will synchronously be reported back - * to the caller instead, e.g. when detected during do_IO(). - */ - if ( ioinfo[irq]->ui.flags.s_pend || ioinfo[irq]->ui.flags.unready ) - allow4handler = 0; - - /* - * Call device action handler if applicable - */ - if ( allow4handler ) - { - - /* - * We only reset the busy condition when we are sure that no further - * interrupt is pending for the current I/O request (ending_status). - */ - if ( ending_status || !ioinfo[irq]->ui.flags.oper ) - { - ioinfo[irq]->ui.flags.oper = 1; /* dev IS oper */ - - ioinfo[irq]->ui.flags.busy = 0; - ioinfo[irq]->ui.flags.doio = 0; - ioinfo[irq]->ui.flags.haltio = 0; - ioinfo[irq]->ui.flags.fast = 0; - ioinfo[irq]->ui.flags.repall = 0; - ioinfo[irq]->ui.flags.w4final = 0; - - ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS; - ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FINAL_STATUS; - - action->handler( irq, action->dev_id, ®s); - - // - // reset intparm after final status or we will badly present unsolicited - // interrupts with a intparm value possibly no longer valid. - // - ioinfo[irq]->devstat.intparm = 0; - - // - // Was there anything queued ? Start the pending channel program - // if there is one. - // - if ( ioinfo[irq]->ui.flags.doio_q ) - { - int ret; - - ret = s390_start_IO( irq, - ioinfo[irq]->qcpa, - ioinfo[irq]->qintparm, - ioinfo[irq]->qlpm, - ioinfo[irq]->qflag); - - ioinfo[irq]->ui.flags.doio_q = 0; - - /* - * If s390_start_IO() failed call the device's interrupt - * handler, the IRQ related devstat area was setup by - * s390_start_IO() accordingly already (status pending - * condition). - */ - if ( ret ) - { - action->handler( irq, action->dev_id, ®s); - - } /* endif */ - - } /* endif */ - - } - else - { - ioinfo[irq]->ui.flags.w4final = 1; - action->handler( irq, action->dev_id, ®s); - - } /* endif */ - - } /* endif */ - - break; - - case 3: /* device not operational */ - - ioinfo[irq]->ui.flags.oper = 0; - - ioinfo[irq]->ui.flags.busy = 0; - ioinfo[irq]->ui.flags.doio = 0; - ioinfo[irq]->ui.flags.haltio = 0; - - ioinfo[irq]->devstat.cstat = 0; - ioinfo[irq]->devstat.dstat = 0; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS; - - /* - * When we find a device "not oper" we save the status - * information into the device status area and call the - * device specific interrupt handler. - * - * Note: currently we don't have any way to reenable - * the device unless an unsolicited interrupt - * is presented. We don't check for spurious - * interrupts on "not oper" conditions. - */ - - if ( ( ioinfo[irq]->ui.flags.fast ) - && ( ioinfo[irq]->ui.flags.w4final ) ) - { - /* - * If a new request was queued already, we have - * to simulate the "not oper" status for the - * queued request by switching the "intparm" value - * and notify the interrupt handler. - */ - if ( ioinfo[irq]->ui.flags.doio_q ) - { - ioinfo[irq]->devstat.intparm = ioinfo[irq]->qintparm; - - } /* endif */ - - } /* endif */ - - ioinfo[irq]->ui.flags.fast = 0; - ioinfo[irq]->ui.flags.repall = 0; - ioinfo[irq]->ui.flags.w4final = 0; - - memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat ); - - ioinfo[irq]->devstat.intparm = 0; - - if ( !ioinfo[irq]->ui.flags.s_pend ) - action->handler( irq, action->dev_id, ®s); - - ending_status = 1; - - break; - - } /* endswitch */ - - return( ending_status ); -} - -/* - * Set the special i/o-interruption sublass 7 for the - * device specified by parameter irq. There can only - * be a single device been operated on this special - * isc. This function is aimed being able to check - * on special device interrupts in disabled state, - * without having to delay I/O processing (by queueing) - * for non-console devices. - * - * Setting of this isc is done by set_cons_dev(), while - * reset_cons_dev() resets this isc and re-enables the - * default isc3 for this device. wait_cons_dev() allows - * to actively wait on an interrupt for this device in - * disabed state. When the interrupt condition is - * encountered, wait_cons_dev(9 calls do_IRQ() to have - * the console device driver processing the interrupt. - */ -int set_cons_dev( int irq ) -{ - int ccode; - unsigned long cr6 __attribute__ ((aligned (8))); - int rc = 0; - - if ( cons_dev != -1 ) - { - rc = -EBUSY; - } - else if ( (irq > highest_subchannel) || (irq < 0) ) - { - rc = -ENODEV; - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - else - { - /* - * modify the indicated console device to operate - * on special console interrupt sublass 7 - */ - ccode = stsch( irq, &(ioinfo[irq]->schib) ); - - if (ccode) - { - rc = -ENODEV; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - } - else - { - ioinfo[irq]->schib.pmcw.isc = 7; - - ccode = msch( irq, &(ioinfo[irq]->schib) ); - - if (ccode) - { - rc = -EIO; - } - else - { - cons_dev = irq; - - /* - * enable console I/O-interrupt sublass 7 - */ - asm volatile ("STCTL 6,6,%0": "=m" (cr6)); - cr6 |= 0x01000000; - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - } /* endif */ - - } /* endif */ - - } /* endif */ - - return( rc); -} - -int reset_cons_dev( int irq) -{ - int rc = 0; - int ccode; - long cr6 __attribute__ ((aligned (8))); - - if ( cons_dev != -1 ) - { - rc = -EBUSY; - } - else if ( (irq > highest_subchannel) || (irq < 0) ) - { - rc = -ENODEV; - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - else - { - /* - * reset the indicated console device to operate - * on default console interrupt sublass 3 - */ - ccode = stsch( irq, &(ioinfo[irq]->schib) ); - - if (ccode) - { - rc = -ENODEV; - ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; - } - else - { - - ioinfo[irq]->schib.pmcw.isc = 3; - - ccode = msch( irq, &(ioinfo[irq]->schib) ); - - if (ccode) - { - rc = -EIO; - } - else - { - cons_dev = -1; - - /* - * disable special console I/O-interrupt sublass 7 - */ - asm volatile ("STCTL 6,6,%0": "=m" (cr6)); - cr6 &= 0xFEFFFFFF; - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - } /* endif */ - - } /* endif */ - - } /* endif */ - - return( rc); -} - -int wait_cons_dev( int irq ) -{ - int rc = 0; - long save_cr6; - - if ( irq == cons_dev ) - { - - /* - * before entering the spinlock we may already have - * processed the interrupt on a different CPU ... - */ - if ( ioinfo[irq]->ui.flags.busy == 1 ) - { - long cr6 __attribute__ ((aligned (8))); - - /* - * disable all, but isc 7 (console device) - */ - asm volatile ("STCTL 6,6,%0": "=m" (cr6)); - save_cr6 = cr6; - cr6 &= 0x01FFFFFF; - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - do { - tpi_info_t tpi_info; - if (tpi(&tpi_info) == 1) { - s390_process_IRQ( tpi_info.irq ); - } else { - s390irq_spin_unlock(irq); - tod_wait(100); - s390irq_spin_lock(irq); - } - eieio(); - } while (ioinfo[irq]->ui.flags.busy == 1); - - /* - * restore previous isc value - */ - asm volatile ("STCTL 6,6,%0": "=m" (cr6)); - cr6 = save_cr6; - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - } /* endif */ - - } - else - { - rc = EINVAL; - - } /* endif */ - - - return(rc); -} - - -int enable_cpu_sync_isc( int irq ) -{ - int ccode; - long cr6 __attribute__ ((aligned (8))); - - int count = 0; - int rc = 0; - - if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA ) - { - ccode = stsch( irq, &(ioinfo[irq]->schib) ); - - if ( !ccode ) - { - ioinfo[irq]->schib.pmcw.isc = 5; - - do - { - ccode = msch( irq, &(ioinfo[irq]->schib) ); - - if (ccode == 0 ) - { - /* - * enable interrupt subclass in CPU - */ - asm volatile ("STCTL 6,6,%0": "=m" (cr6)); - cr6 |= 0x04000000; // enable sync isc 5 - cr6 &= 0xEFFFFFFF; // disable standard isc 3 - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - } - else if (ccode == 3) - { - rc = -ENODEV; // device not-oper - very unlikely - - } - else if (ccode == 2) - { - rc = -EBUSY; // device busy - should not happen - - } - else if (ccode == 1) - { - // - // process pending status - // - ioinfo[irq]->ui.flags.s_pend = 1; - - s390_process_IRQ( irq ); - - ioinfo[irq]->ui.flags.s_pend = 0; - - count++; - - } /* endif */ - - } while ( ccode == 1 && count < 3 ); - - if ( count == 3) - { - rc = -EIO; - - } /* endif */ - } - else - { - rc = -ENODEV; // device is not-operational - - } /* endif */ - } - else - { - rc = -EINVAL; - - } /* endif */ - - return( rc); -} - -int disable_cpu_sync_isc( int irq) -{ - int rc = 0; - int ccode; - long cr6 __attribute__ ((aligned (8))); - - if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA ) - { - ccode = stsch( irq, &(ioinfo[irq]->schib) ); - - ioinfo[irq]->schib.pmcw.isc = 3; - - ccode = msch( irq, &(ioinfo[irq]->schib) ); - - if (ccode) - { - rc = -EIO; - } - else - { - - /* - * enable interrupt subclass in CPU - */ - asm volatile ("STCTL 6,6,%0": "=m" (cr6)); - cr6 &= 0xFBFFFFFF; // disable sync isc 5 - cr6 |= 0x10000000; // enable standard isc 3 - asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); - - } /* endif */ - - } - else - { - rc = -EINVAL; - - } /* endif */ - - return( rc); -} - -// -// Input : -// devno - device number -// ps - pointer to sense ID data area -// -// Output : none -// -void VM_virtual_device_info( __u16 devno, - senseid_t *ps ) -{ - diag210_t diag_data; - int ccode; - - int error = 0; - - diag_data.vrdcdvno = devno; - diag_data.vrdclen = sizeof( diag210_t); - ccode = diag210( (diag210_t *)virt_to_phys( &diag_data ) ); - ps->reserved = 0xff; - - switch (diag_data.vrdcvcla) { - case 0x80: - - switch (diag_data.vrdcvtyp) { - case 00: - - ps->cu_type = 0x3215; - - break; - - default: - - error = 1; - - break; - - } /* endswitch */ - - break; - - case 0x40: - - switch (diag_data.vrdcvtyp) { - case 0xC0: - - ps->cu_type = 0x5080; - - break; - - case 0x80: - - ps->cu_type = 0x2250; - - break; - - case 0x04: - - ps->cu_type = 0x3277; - - break; - - case 0x01: - - ps->cu_type = 0x3278; - - break; - - default: - - error = 1; - - break; - - } /* endswitch */ - - break; - - case 0x20: - - switch (diag_data.vrdcvtyp) { - case 0x84: - - ps->cu_type = 0x3505; - - break; - - case 0x82: - - ps->cu_type = 0x2540; - - break; - - case 0x81: - - ps->cu_type = 0x2501; - - break; - - default: - - error = 1; - - break; - - } /* endswitch */ - - break; - - case 0x10: - - switch (diag_data.vrdcvtyp) { - case 0x84: - - ps->cu_type = 0x3525; - - break; - - case 0x82: - - ps->cu_type = 0x2540; - - break; - - case 0x4F: - case 0x4E: - case 0x48: - - ps->cu_type = 0x3820; - - break; - - case 0x4D: - case 0x49: - case 0x45: - - ps->cu_type = 0x3800; - - break; - - case 0x4B: - - ps->cu_type = 0x4248; - - break; - - case 0x4A: - - ps->cu_type = 0x4245; - - break; - - case 0x47: - - ps->cu_type = 0x3262; - - break; - - case 0x43: - - ps->cu_type = 0x3203; - - break; - - case 0x42: - - ps->cu_type = 0x3211; - - break; - - case 0x41: - - ps->cu_type = 0x1403; - - break; - - default: - - error = 1; - - break; - - } /* endswitch */ - - break; - - case 0x08: - - switch (diag_data.vrdcvtyp) { - case 0x82: - - ps->cu_type = 0x3422; - - break; - - case 0x81: - - ps->cu_type = 0x3490; - - break; - - case 0x10: - - ps->cu_type = 0x3420; - - break; - - case 0x02: - - ps->cu_type = 0x3430; - - break; - - case 0x01: - - ps->cu_type = 0x3480; - - break; - - case 0x42: - - ps->cu_type = 0x3424; - - break; - - case 0x44: - - ps->cu_type = 0x9348; - - break; - - default: - - error = 1; - - break; - - } /* endswitch */ - - break; - - default: - - error = 1; - - break; - - } /* endswitch */ - - if ( error ) - {printk( "DIAG X'210' for device %04X returned (cc = %d): vdev class : %02X, " - "vdev type : %04X \n ... rdev class : %02X, rdev type : %04X, rdev model: %02X\n", - devno, - ccode, - diag_data.vrdcvcla, - diag_data.vrdcvtyp, - diag_data.vrdcrccl, - diag_data.vrdccrty, - diag_data.vrdccrmd ); - - } /* endif */ - -} - -/* - * This routine returns the characteristics for the device - * specified. Some old devices might not provide the necessary - * command code information during SenseID processing. In this - * case the function returns -EINVAL. Otherwise the function - * allocates a decice specific data buffer and provides the - * device characteristics together with the buffer size. Its - * the callers responability to release the kernel memory if - * not longer needed. In case of persistent I/O problems -EBUSY - * is returned. - * - * The function may be called enabled or disabled. However, the - * caller must have locked the irq it is requesting data for. - * - * Note : It would have been nice to collect this information - * during init_IRQ() processing but this is not possible - * - * a) without statically pre-allocation fixed size buffers - * as virtual memory management isn't available yet. - * - * b) without unnecessarily increase system startup by - * evaluating devices eventually not used at all. - */ -int read_dev_chars( int irq, void **buffer, int length ) -{ - unsigned int flags; - ccw1_t *rdc_ccw; - devstat_t devstat; - char *rdc_buf; - int devflag; - - int ret = 0; - int emulated = 0; - int retry = 5; - - if ( !buffer || !length ) - { - return( -EINVAL ); - - } /* endif */ - - if ( (irq > highest_subchannel) || (irq < 0 ) ) - { - return( -ENODEV ); - - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - - if ( ioinfo[irq]->ui.flags.oper == 0 ) - { - return( -ENODEV ); - - } /* endif */ - - /* - * Before playing around with irq locks we should assure - * running disabled on (just) our CPU. Sync. I/O requests - * also require to run disabled. - * - * Note : as no global lock is required, we must not use - * cli(), but __cli() instead. - */ - __save_flags(flags); - __cli(); - - rdc_ccw = &ioinfo[irq]->senseccw; - - if ( !ioinfo[irq]->ui.flags.ready ) - { - ret = request_irq( irq, - init_IRQ_handler, - 0, "RDC", &devstat ); - - if ( !ret ) - { - emulated = 1; - - } /* endif */ - - } /* endif */ - - if ( !ret ) - { - if ( ! *buffer ) - { - rdc_buf = kmalloc( length, GFP_KERNEL); - } - else - { - rdc_buf = *buffer; - - } /* endif */ - - if ( !rdc_buf ) - { - ret = -ENOMEM; - } - else - { - do - { - rdc_ccw->cmd_code = CCW_CMD_RDC; - rdc_ccw->cda = (__u32)virt_to_phys( rdc_buf ); - rdc_ccw->count = length; - rdc_ccw->flags = CCW_FLAG_SLI; - - ret = s390_start_IO( irq, - rdc_ccw, - 0x00524443, // RDC - 0, // n/a - DOIO_WAIT_FOR_INTERRUPT ); - retry--; - devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag; - - } while ( ( retry ) - && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) ); - - } /* endif */ - - if ( !retry ) - { - ret = -EBUSY; - - } /* endif */ - - __restore_flags(flags); - - /* - * on success we update the user input parms - */ - if ( !ret ) - { - *buffer = rdc_buf; - - } /* endif */ - - if ( emulated ) - { - free_irq( irq, &devstat); - - } /* endif */ - - } /* endif */ - - return( ret ); -} - -/* - * Read Configuration data - */ -int read_conf_data( int irq, void **buffer, int *length ) -{ - int found = 0; - int ciw_cnt = 0; - unsigned int flags; - - int ret = 0; - - if ( (irq > highest_subchannel) || (irq < 0 ) ) - { - return( -ENODEV ); - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - - } /* endif */ - - if ( ioinfo[irq]->ui.flags.oper == 0 ) - { - return( -ENODEV ); - - } /* endif */ - - /* - * scan for RCD command in extended SenseID data - */ - for ( ; (found == 0) && (ciw_cnt < 62); ciw_cnt++ ) - { - if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD ) - { - found = 1; - break; - } /* endif */ - - } /* endfor */ - - if ( found ) - { - ccw1_t *rcd_ccw = &ioinfo[irq]->senseccw; - devstat_t devstat; - char *rcd_buf; - int devflag; - - int emulated = 0; - int retry = 5; - - __save_flags(flags); - __cli(); - - if ( !ioinfo[irq]->ui.flags.ready ) - { - ret = request_irq( irq, - init_IRQ_handler, - 0, "RCD", &devstat ); - - if ( !ret ) - { - emulated = 1; - - } /* endif */ - - } /* endif */ - - if ( !ret ) - { - rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count, - GFP_KERNEL); - - do - { - rcd_ccw->cmd_code = ioinfo[irq]->senseid.ciw[ciw_cnt].cmd; - rcd_ccw->cda = (__u32)virt_to_phys( rcd_buf ); - rcd_ccw->count = ioinfo[irq]->senseid.ciw[ciw_cnt].count; - rcd_ccw->flags = CCW_FLAG_SLI; - - ret = s390_start_IO( irq, - rcd_ccw, - 0x00524344, // == RCD - 0, // n/a - DOIO_WAIT_FOR_INTERRUPT ); - - retry--; - - devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag; - - } while ( ( retry ) - && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) ); - - if ( !retry ) - ret = -EBUSY; - - __restore_flags(flags); - - } /* endif */ - - /* - * on success we update the user input parms - */ - if ( !ret ) - { - *length = ioinfo[irq]->senseid.ciw[ciw_cnt].count; - *buffer = rcd_buf; - - } /* endif */ - - if ( emulated ) - free_irq( irq, &devstat); - } - else - { - ret = -EINVAL; - - } /* endif */ - - return( ret ); - -} - -int get_dev_info( int irq, dev_info_t * pdi) -{ - return( get_dev_info_by_irq( irq, pdi)); -} - -static int __inline__ get_next_available_irq( ioinfo_t *pi) -{ - int ret_val; - - while ( TRUE ) - { - if ( pi->ui.flags.oper ) - { - ret_val = pi->irq; - break; - } - else - { - pi = pi->next; - - // - // leave at end of list unconditionally - // - if ( pi == NULL ) - { - ret_val = -ENODEV; - break; - } - - } /* endif */ - - } /* endwhile */ - - return ret_val; -} - - -int get_irq_first( void ) -{ - int ret_irq; - - if ( ioinfo_head ) - { - if ( ioinfo_head->ui.flags.oper ) - { - ret_irq = ioinfo_head->irq; - } - else if ( ioinfo_head->next ) - { - ret_irq = get_next_available_irq( ioinfo_head->next ); - - } - else - { - ret_irq = -ENODEV; - - } /* endif */ - } - else - { - ret_irq = -ENODEV; - - } /* endif */ - - return ret_irq; -} - -int get_irq_next( int irq ) -{ - int ret_irq; - - if ( ioinfo[irq] != INVALID_STORAGE_AREA ) - { - if ( ioinfo[irq]->next ) - { - if ( ioinfo[irq]->next->ui.flags.oper ) - { - ret_irq = ioinfo[irq]->next->irq; - } - else - { - ret_irq = get_next_available_irq( ioinfo[irq]->next ); - - } /* endif */ - } - else - { - ret_irq = -ENODEV; - - } /* endif */ - } - else - { - ret_irq = -EINVAL; - - } /* endif */ - - return ret_irq; -} - -int get_dev_info_by_irq( int irq, dev_info_t *pdi) -{ - - if ( irq > highest_subchannel || irq < 0 ) - { - return -ENODEV; - } - else if ( pdi == NULL ) - { - return -EINVAL; - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } - else - { - pdi->devno = ioinfo[irq]->schib.pmcw.dev; - pdi->irq = irq; - - if ( ioinfo[irq]->ui.flags.oper ) - { - pdi->status = 0; - memcpy( &(pdi->sid_data), - &ioinfo[irq]->senseid, - sizeof( senseid_t)); - } - else - { - pdi->status = DEVSTAT_NOT_OPER; - memcpy( &(pdi->sid_data), - '\0', - sizeof( senseid_t)); - pdi->sid_data.cu_type = 0xFFFF; - - } /* endif */ - - if ( ioinfo[irq]->ui.flags.ready ) - pdi->status |= DEVSTAT_DEVICE_OWNED; - - return 0; - - } /* endif */ - -} - - -int get_dev_info_by_devno( __u16 devno, dev_info_t *pdi) -{ - int i; - int rc = -ENODEV; - - if ( devno > 0x0000ffff ) - { - return -ENODEV; - } - else if ( pdi == NULL ) - { - return -EINVAL; - } - else - { - - for ( i=0; i <= highest_subchannel; i++ ) - { - - if ( ioinfo[i] != INVALID_STORAGE_AREA - && ioinfo[i]->schib.pmcw.dev == devno ) - { - if ( ioinfo[i]->ui.flags.oper ) - { - pdi->status = 0; - pdi->irq = i; - pdi->devno = devno; - - memcpy( &(pdi->sid_data), - &ioinfo[i]->senseid, - sizeof( senseid_t)); - } - else - { - pdi->status = DEVSTAT_NOT_OPER; - pdi->irq = i; - pdi->devno = devno; - - memcpy( &(pdi->sid_data), '\0', sizeof( senseid_t)); - pdi->sid_data.cu_type = 0xFFFF; - - } /* endif */ - - if ( ioinfo[i]->ui.flags.ready ) - pdi->status |= DEVSTAT_DEVICE_OWNED; - - rc = 0; /* found */ - break; - - } /* endif */ - - } /* endfor */ - - return( rc); - - } /* endif */ - -} - -int get_irq_by_devno( __u16 devno ) -{ - int i; - int rc = -1; - - if ( devno <= 0x0000ffff ) - { - for ( i=0; i <= highest_subchannel; i++ ) - { - if ( (ioinfo[i] != INVALID_STORAGE_AREA ) - && (ioinfo[i]->schib.pmcw.dev == devno) - && (ioinfo[i]->schib.pmcw.dnv == 1 ) ) - { - rc = i; - break; - - } /* endif */ - - } /* endfor */ - - } /* endif */ - - return( rc); -} - -unsigned int get_devno_by_irq( int irq ) -{ - - if ( ( irq > highest_subchannel ) - || ( irq < 0 ) - || ( ioinfo[irq] == INVALID_STORAGE_AREA ) ) - { - return -1; - - } /* endif */ - - /* - * we don't need to check for the device be operational - * as the initial STSCH will always present the device - * number defined by the IOCDS regardless of the device - * existing or not. However, there could be subchannels - * defined who's device number isn't valid ... - */ - if ( ioinfo[irq]->schib.pmcw.dnv ) - return( ioinfo[irq]->schib.pmcw.dev ); - else - return -1; -} - -/* - * s390_device_recognition - * - * Used for system wide device recognition. Issues the device - * independant SenseID command to obtain info the device type. - * - */ -void s390_device_recognition( void) -{ - - int irq = 0; /* let's start with subchannel 0 ... */ - - do - { - /* - * We issue the SenseID command on I/O subchannels we think are - * operational only. - */ - if ( ( ioinfo[irq] != INVALID_STORAGE_AREA ) - && ( ioinfo[irq]->schib.pmcw.st == 0 ) - && ( ioinfo[irq]->ui.flags.oper == 1 ) ) - { - s390_SenseID( irq, &ioinfo[irq]->senseid ); - - } /* endif */ - - irq ++; - - } while ( irq <= highest_subchannel ); - -} - - -/* - * s390_search_devices - * - * Determines all subchannels available to the system. - * - */ -void s390_process_subchannels( void) -{ - int isValid; - int irq = 0; /* Evaluate all subchannels starting with 0 ... */ - - do - { - isValid = s390_validate_subchannel( irq); - - irq++; - - } while ( isValid && irq < __MAX_SUBCHANNELS ); - - highest_subchannel = --irq; - - printk( "\nHighest subchannel number detected: %u\n", - highest_subchannel); -} - -/* - * s390_validate_subchannel() - * - * Process the subchannel for the requested irq. Returns 1 for valid - * subchannels, otherwise 0. - */ -int s390_validate_subchannel( int irq ) -{ - - int retry; /* retry count for status pending conditions */ - int ccode; /* condition code for stsch() only */ - int ccode2; /* condition code for other I/O routines */ - schib_t *p_schib; - - /* - * The first subchannel that is not-operational (ccode==3) - * indicates that there aren't any more devices available. - */ - if ( ( init_IRQ_complete ) - && ( ioinfo[irq] != INVALID_STORAGE_AREA ) ) - { - p_schib = &ioinfo[irq]->schib; - } - else - { - p_schib = &init_schib; - - } /* endif */ - - ccode = stsch( irq, p_schib); - - if ( ccode == 0) - { - /* - * ... just being curious we check for non I/O subchannels - */ - if ( p_schib->pmcw.st ) - { - printk( "Subchannel %04X reports " - "non-I/O subchannel type %04X\n", - irq, - p_schib->pmcw.st); - - if ( ioinfo[irq] != INVALID_STORAGE_AREA ) - ioinfo[irq]->ui.flags.oper = 0; - - } /* endif */ - - if ( p_schib->pmcw.dnv ) - { - if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - - if ( !init_IRQ_complete ) - { - ioinfo[irq] = - (ioinfo_t *)alloc_bootmem( sizeof(ioinfo_t)); - } - else - { - ioinfo[irq] = - (ioinfo_t *)kmalloc( sizeof(ioinfo_t), - GFP_KERNEL ); - - } /* endif */ - - memset( ioinfo[irq], '\0', sizeof( ioinfo_t)); - memcpy( &ioinfo[irq]->schib, - &init_schib, - sizeof( schib_t)); - ioinfo[irq]->irq_desc.status = IRQ_DISABLED; - ioinfo[irq]->irq_desc.handler = &no_irq_type; - - /* - * We have to insert the new ioinfo element - * into the linked list, either at its head, - * its tail or insert it. - */ - if ( ioinfo_head == NULL ) /* first element */ - { - ioinfo_head = ioinfo[irq]; - ioinfo_tail = ioinfo[irq]; - } - else if ( irq < ioinfo_head->irq ) /* new head */ - { - ioinfo[irq]->next = ioinfo_head; - ioinfo_head->prev = ioinfo[irq]; - ioinfo_head = ioinfo[irq]; - } - else if ( irq > ioinfo_tail->irq ) /* new tail */ - { - ioinfo_tail->next = ioinfo[irq]; - ioinfo[irq]->prev = ioinfo_tail; - ioinfo_tail = ioinfo[irq]; - } - else /* insert element */ - { - ioinfo_t *pi = ioinfo_head; - - do - { - if ( irq < pi->next->irq ) - { - ioinfo[irq]->next = pi->next; - ioinfo[irq]->prev = pi; - pi->next->prev = ioinfo[irq]; - pi->next = ioinfo[irq]; - break; - - } /* endif */ - - pi = pi->next; - - } while ( 1 ); - - } /* endif */ - - } /* endif */ - - // initialize some values ... - ioinfo[irq]->ui.flags.pgid_supp = 1; - - ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pam - & ioinfo[irq]->schib.pmcw.pom; - - printk( "Detected device %04X on subchannel %04X" - " - PIM = %02X, PAM = %02X, POM = %02X\n", - ioinfo[irq]->schib.pmcw.dev, - irq, - ioinfo[irq]->schib.pmcw.pim, - ioinfo[irq]->schib.pmcw.pam, - ioinfo[irq]->schib.pmcw.pom); - - /* - * We should have at least one CHPID ... - */ - if ( ioinfo[irq]->schib.pmcw.pim - & ioinfo[irq]->schib.pmcw.pam - & ioinfo[irq]->schib.pmcw.pom ) - { - ioinfo[irq]->ui.flags.oper = 0; - - /* - * We now have to initially ... - * ... set "interruption sublass" - * ... enable "concurrent sense" - * ... enable "multipath mode" if more than one - * CHPID is available. This is done regardless - * whether multiple paths are available for us. - * - * Note : we don't enable the device here, this is temporarily - * done during device sensing below. - */ - ioinfo[irq]->schib.pmcw.isc = 3; /* could be smth. else */ - ioinfo[irq]->schib.pmcw.csense = 1; /* concurrent sense */ - ioinfo[irq]->schib.pmcw.ena = 0; /* force disable it */ - ioinfo[irq]->schib.pmcw.intparm = - ioinfo[irq]->schib.pmcw.dev; - - if ( ( ioinfo[irq]->schib.pmcw.pim != 0 ) - && ( ioinfo[irq]->schib.pmcw.pim != 0x80 ) ) - { - ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */ - - } /* endif */ - - /* - * initialize ioinfo structure - */ - ioinfo[irq]->irq = irq; - ioinfo[irq]->ui.flags.busy = 0; - ioinfo[irq]->ui.flags.ready = 0; - ioinfo[irq]->ui.flags.oper = 1; - ioinfo[irq]->devstat.intparm = 0; - ioinfo[irq]->devstat.devno = ioinfo[irq]->schib.pmcw.dev; - - retry = 5; - - do - { - ccode2 = msch_err( irq, &ioinfo[irq]->schib); - - switch (ccode2) { - case 0: // successful completion - // - // concurrent sense facility available ... - // - ioinfo[irq]->ui.flags.consns = 1; - break; - - case 1: // status pending - // - // How can we have a pending status as device is - // disabled for interrupts ? Anyway, clear it ... - // - tsch( irq, &(ioinfo[irq]->devstat.ii.irb) ); - retry--; - break; - - case 2: // busy - retry--; - break; - - case 3: // not operational - ioinfo[irq]->ui.flags.oper = 0; - retry = 0; - break; - - default: -#define PGMCHK_OPERAND_EXC 0x15 - - if ( (ccode2 & PGMCHK_OPERAND_EXC) == PGMCHK_OPERAND_EXC ) - { - /* - * re-issue the modify subchannel without trying to - * enable the concurrent sense facility - */ - ioinfo[irq]->schib.pmcw.csense = 0; - - ccode2 = msch_err( irq, &ioinfo[irq]->schib); - - if ( ccode2 != 0 ) - { - printk( " ... modify subchannel (2) failed with CC = %X\n", - ccode2 ); - ioinfo[irq]->ui.flags.oper = 0; - } - else - { - ioinfo[irq]->ui.flags.consns = 0; - - } /* endif */ - } - else - { - printk( " ... modify subchannel (1) failed with CC = %X\n", - ccode2); - ioinfo[irq]->ui.flags.oper = 0; - - } /* endif */ - - retry = 0; - break; - - } /* endswitch */ - - } while ( ccode2 && retry ); - - if ( (ccode2 < 3) && (!retry) ) - { - printk( " ... msch() retry count for " - "subchannel %04X exceeded, CC = %d\n", - irq, - ccode2); - - } /* endif */ - - } - else - { - ioinfo[irq]->ui.flags.oper = 0; - - } /* endif */ - - } /* endif */ - - } /* endif */ - - /* - * indicate whether the subchannel is valid - */ - if ( ccode == 3) - return(0); - else - return(1); -} - -/* - * s390_SenseID - * - * Try to obtain the 'control unit'/'device type' information - * associated with the subchannel. - * - * The function is primarily meant to be called without irq - * action handler in place. However, it also allows for - * use with an action handler in place. If there is already - * an action handler registered assure it can handle the - * s390_SenseID() related device interrupts - interruption - * parameter used is 0x00E2C9C4 ( SID ). - */ -int s390_SenseID( int irq, senseid_t *sid ) -{ - ccw1_t sense_ccw; /* ccw area for SenseID command */ - devstat_t devstat; /* required by request_irq() */ - - int irq_ret = 0; /* return code */ - int retry = 5; /* retry count */ - int inlreq = 0; /* inline request_irq() */ - - if ( (irq > highest_subchannel) || (irq < 0 ) ) - { - return( -ENODEV ); - - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - } /* endif */ - - if ( ioinfo[irq]->ui.flags.oper == 0 ) - { - return( -ENODEV ); - - } /* endif */ - - if ( !ioinfo[irq]->ui.flags.ready ) - { - /* - * Perform SENSE ID command processing. We have to request device - * ownership and provide a dummy I/O handler. We issue sync. I/O - * requests and evaluate the devstat area on return therefore - * we don't need a real I/O handler in place. - */ - irq_ret = request_irq( irq, init_IRQ_handler, 0, "SID", &devstat); - - if ( irq_ret == 0 ) - inlreq = 1; - - } /* endif */ - - if ( irq_ret == 0 ) - { - s390irq_spin_lock( irq); - - sense_ccw.cmd_code = CCW_CMD_SENSE_ID; - sense_ccw.cda = (__u32)virt_to_phys( sid ); - sense_ccw.count = sizeof( senseid_t); - sense_ccw.flags = CCW_FLAG_SLI; - - ioinfo[irq]->senseid.cu_type = 0xFFFF; /* initialize fields ... */ - ioinfo[irq]->senseid.cu_model = 0; - ioinfo[irq]->senseid.dev_type = 0; - ioinfo[irq]->senseid.dev_model = 0; - - /* - * We now issue a SenseID request. In case of BUSY - * or STATUS PENDING conditions we retry 5 times. - */ - do - { - memset( &devstat, '\0', sizeof( devstat_t) ); - - irq_ret = s390_start_IO( irq, - &sense_ccw, - 0x00E2C9C4, // == SID - 0, // n/a - DOIO_WAIT_FOR_INTERRUPT - | DOIO_TIMEOUT ); - - if ( irq_ret == -ETIMEDOUT ) - { - halt_IO( irq, - 0x80E2C9C4, - DOIO_WAIT_FOR_INTERRUPT); - devstat.flag |= DEVSTAT_NOT_OPER; - - } /* endif */ - - if ( sid->cu_type == 0xFFFF && devstat.flag != DEVSTAT_NOT_OPER ) - { - if ( devstat.flag & DEVSTAT_STATUS_PENDING ) - { -#if CONFIG_DEBUG_IO - printk( "Device %04X on Subchannel %04X " - "reports pending status, retry : %d\n", - ioinfo[irq]->schib.pmcw.dev, - irq, - retry); -#endif - } /* endif */ - - if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL ) - { - /* - * if the device doesn't support the SenseID - * command further retries wouldn't help ... - */ - if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT ) - { - retry = 0; - } -#if CONFIG_DEBUG_IO - else - { - printk( "Device %04X," - " UC/SenseID," - " retry %d, cnt %02d," - " sns :" - " %02X%02X%02X%02X %02X%02X%02X%02X ...\n", - ioinfo[irq]->schib.pmcw.dev, - retry, - devstat.scnt, - devstat.ii.sense.data[0], - devstat.ii.sense.data[1], - devstat.ii.sense.data[2], - devstat.ii.sense.data[3], - devstat.ii.sense.data[4], - devstat.ii.sense.data[5], - devstat.ii.sense.data[6], - devstat.ii.sense.data[7]); - - } /* endif */ -#endif - } - else if ( devstat.flag & DEVSTAT_NOT_OPER ) - { - printk( "Device %04X on Subchannel %04X " - "became 'not operational'\n", - ioinfo[irq]->schib.pmcw.dev, - irq); - - retry = 0; - - } /* endif */ - } - else // we got it or the device is not-operational ... - { - retry = 0; - - } /* endif */ - - retry--; - - } while ( retry > 0 ); - - s390irq_spin_unlock( irq); - - /* - * If we installed the irq action handler we have to - * release it too. - */ - if ( inlreq ) - free_irq( irq, &devstat); - - /* - * if running under VM check there ... perhaps we should do - * only if we suffered a command reject, but it doesn't harm - */ - if ( ( sid->cu_type == 0xFFFF ) - && ( MACHINE_IS_VM ) ) - { - VM_virtual_device_info( ioinfo[irq]->schib.pmcw.dev, - sid ); - } /* endif */ - - if ( sid->cu_type == 0xFFFF ) - { - /* - * SenseID CU-type of 0xffff indicates that no device - * information could be retrieved (pre-init value). - * - * If we can't couldn't identify the device type we - * consider the device "not operational". - */ - printk( "Unknown device %04X on subchannel %04X\n", - ioinfo[irq]->schib.pmcw.dev, - irq); - ioinfo[irq]->ui.flags.oper = 0; - - } /* endif */ - - /* - * Issue device info message if unit was operational . - */ - if ( ioinfo[irq]->ui.flags.oper ) - { - if ( sid->dev_type != 0 ) - { - printk( "Device %04X reports: CU Type/Mod = %04X/%02X," - " Dev Type/Mod = %04X/%02X\n", - ioinfo[irq]->schib.pmcw.dev, - sid->cu_type, - sid->cu_model, - sid->dev_type, - sid->dev_model); - } - else - { - printk( "Device %04X reports:" - " Dev Type/Mod = %04X/%02X\n", - ioinfo[irq]->schib.pmcw.dev, - sid->cu_type, - sid->cu_model); - - } /* endif */ - - } /* endif */ - - if ( ioinfo[irq]->ui.flags.oper ) - irq_ret = 0; - else - irq_ret = -ENODEV; - - } /* endif */ - - return( irq_ret ); -} - -static int __inline__ s390_SetMultiPath( int irq ) -{ - int cc; - - cc = stsch( irq, &ioinfo[irq]->schib ); - - if ( !cc ) - { - ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */ - - cc = msch( irq, &ioinfo[irq]->schib ); - - } /* endif */ - - return( cc); -} - -/* - * Device Path Verification - * - * Path verification is accomplished by checking which paths (CHPIDs) are - * available. Further, a path group ID is set, if possible in multipath - * mode, otherwise in single path mode. - * - */ -int s390_DevicePathVerification( int irq ) -{ -#if 0 - int ccode; - __u8 pathmask; - - int ret = 0; - - if ( ioinfo[irq]->ui.flags.pgid_supp == 0 ) - { - ret = -EOPNOTSUPP; - - } /* endif */ - - ccode = stsch( irq, &(ioinfo[irq]->schib) ); - - if ( ccode ) - { - ret = -ENODEV; - } - else - { - int i; - pgid_t pgid; - - int first = 1; - __u8 dev_path = ioinfo[irq]->schib.pmcw.pam - & ioinfo[irq]->schib.pmcw.pom; - - /* - * let's build a path group ID if we don't have one yet - */ - if ( ioinfo[irq]->ui.flags.pgid == 0) - { - struct _lowcore *lowcore = &get_cpu_lowcore(cpu); - - ioinfo->pgid.cpu_addr = lowcore->cpu_data.cpu_addr; - ioinfo->pgid.cpu_id = lowcore->cpu_data.cpu_id.ident; - ioinfo->pgid.cpu_model = lowcore->cpu_data.cpu_id.machine; - ioinfo->pgid.tod_high = *(__u32 *)&irq_IPL_TOD; - - ioinfo[irq]->ui.flags.pgid = 1; - - } /* endif */ - - memcpy( &pgid, ioinfo[irq]->pgid, sizeof(pgid_t)); - - for ( i = 0; i < 8 && !ret ; i++) - { - pathmask = 0x80 >> i; - - if ( dev_path & pathmask ) - { - ret = s390_SetPGID( irq, pathmask, &pgid ); - - /* - * For the *first* path we are prepared - * for recovery - * - * - If we fail setting the PGID we assume its - * using a different PGID already (VM) we - * try to sense. - */ - if ( ret == -EOPNOTSUPP && first ) - { - *(int *)&pgid = 0; - - ret = s390_SensePGID( irq, pathmask, &pgid); - first = 0; - - if ( !ret ) - { - /* - * Check whether we retrieved - * a reasonable PGID ... - */ - if ( !ret && (*(int *)&pgid == 0) ) - { - ret = -EOPNOTSUPP; - } - else - { - ret = s390_SetPGID( irq, pathmask, &pgid ); - - } /* endif */ - - } /* endif */ - - if ( ret ) - { - ioinfo[irq]->ui.flags.pgid_supp = 0; - - printk( "PathVerification(%04X) " - "- Device %04X doesn't " - " support path grouping", - irq, - ioinfo[irq]->schib.pmcw.dev); - - } /* endif */ - } - else if ( ret ) - { - ioinfo[irq]->ui.flags.pgid_supp = 0; - - } /* endif */ - - } /* endif */ - - } /* endfor */ - - } /* endif */ - - return ret; -#else - return 0; -#endif -} - -/* - * s390_SetPGID - * - * Set Path Group ID - * - */ -int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid ) -{ - ccw1_t spid_ccw; /* ccw area for SPID command */ - devstat_t devstat; /* required by request_irq() */ - - int irq_ret = 0; /* return code */ - int retry = 5; /* retry count */ - int inlreq = 0; /* inline request_irq() */ - int mpath = 1; /* try multi-path first */ - - if ( (irq > highest_subchannel) || (irq < 0 ) ) - { - return( -ENODEV ); - - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - - } /* endif */ - - if ( ioinfo[irq]->ui.flags.oper == 0 ) - { - return( -ENODEV ); - - } /* endif */ - - if ( !ioinfo[irq]->ui.flags.ready ) - { - /* - * Perform SENSE ID command processing. We have to request device - * ownership and provide a dummy I/O handler. We issue sync. I/O - * requests and evaluate the devstat area on return therefore - * we don't need a real I/O handler in place. - */ - irq_ret = request_irq( irq, init_IRQ_handler, 0, "SPID", &devstat); - - if ( irq_ret == 0 ) - inlreq = 1; - - } /* endif */ - - if ( irq_ret == 0 ) - { - s390irq_spin_lock( irq); - - spid_ccw.cmd_code = CCW_CMD_SET_PGID; - spid_ccw.cda = (__u32)virt_to_phys( pgid ); - spid_ccw.count = sizeof( pgid_t); - spid_ccw.flags = CCW_FLAG_SLI; - - - /* - * We now issue a SenseID request. In case of BUSY - * or STATUS PENDING conditions we retry 5 times. - */ - do - { - memset( &devstat, '\0', sizeof( devstat_t) ); - - irq_ret = s390_start_IO( irq, - &spid_ccw, - 0xE2D7C9C4, // == SPID - lpm, // n/a - DOIO_WAIT_FOR_INTERRUPT - | DOIO_VALID_LPM ); - - if ( !irq_ret ) - { - if ( devstat.flag & DEVSTAT_STATUS_PENDING ) - { -#if CONFIG_DEBUG_IO - printk( "SPID - Device %04X " - "on Subchannel %04X " - "reports pending status, " - "retry : %d\n", - ioinfo[irq]->schib.pmcw.dev, - irq, - retry); -#endif - } /* endif */ - - if ( devstat.flag == ( DEVSTAT_START_FUNCTION - | DEVSTAT_FINAL_STATUS ) ) - { - retry = 0; // successfully set ... - } - else if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL ) - { - /* - * If the device doesn't support the - * Sense Path Group ID command - * further retries wouldn't help ... - */ - if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT ) - { - if ( mpath ) - { - pgid->inf.fc = SPID_FUNC_ESTABLISH; - mpath = 0; - retry--; - } - else - { - irq_ret = -EOPNOTSUPP; - retry = 0; - - } /* endif */ - } -#if CONFIG_DEBUG_IO - else - { - printk( "SPID - device %04X," - " unit check," - " retry %d, cnt %02d," - " sns :" - " %02X%02X%02X%02X %02X%02X%02X%02X ...\n", - ioinfo[irq]->schib.pmcw.dev, - retry, - devstat.scnt, - devstat.ii.sense.data[0], - devstat.ii.sense.data[1], - devstat.ii.sense.data[2], - devstat.ii.sense.data[3], - devstat.ii.sense.data[4], - devstat.ii.sense.data[5], - devstat.ii.sense.data[6], - devstat.ii.sense.data[7]); - - } /* endif */ -#endif - } - else if ( devstat.flag & DEVSTAT_NOT_OPER ) - { - printk( "SPID - Device %04X " - "on Subchannel %04X " - "became 'not operational'\n", - ioinfo[irq]->schib.pmcw.dev, - irq); - - retry = 0; - - } /* endif */ - } - else if ( irq_ret != -ENODEV ) - { - retry--; - } - else - { - retry = 0; - - } /* endif */ - - } while ( retry > 0 ); - - s390irq_spin_unlock( irq); - - /* - * If we installed the irq action handler we have to - * release it too. - */ - if ( inlreq ) - free_irq( irq, &devstat); - - } /* endif */ - - return( irq_ret ); -} - - -/* - * s390_SensePGID - * - * Sense Path Group ID - * - */ -int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid ) -{ - ccw1_t snid_ccw; /* ccw area for SNID command */ - devstat_t devstat; /* required by request_irq() */ - - int irq_ret = 0; /* return code */ - int retry = 5; /* retry count */ - int inlreq = 0; /* inline request_irq() */ - - if ( (irq > highest_subchannel) || (irq < 0 ) ) - { - return( -ENODEV ); - - } - else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) - { - return( -ENODEV); - - } /* endif */ - - if ( ioinfo[irq]->ui.flags.oper == 0 ) - { - return( -ENODEV ); - - } /* endif */ - - if ( !ioinfo[irq]->ui.flags.ready ) - { - /* - * Perform SENSE ID command processing. We have to request device - * ownership and provide a dummy I/O handler. We issue sync. I/O - * requests and evaluate the devstat area on return therefore - * we don't need a real I/O handler in place. - */ - irq_ret = request_irq( irq, init_IRQ_handler, 0, "SNID", &devstat); - - if ( irq_ret == 0 ) - inlreq = 1; - - } /* endif */ - - if ( irq_ret == 0 ) - { - s390irq_spin_lock( irq); - - snid_ccw.cmd_code = CCW_CMD_SENSE_PGID; - snid_ccw.cda = (__u32)virt_to_phys( pgid ); - snid_ccw.count = sizeof( pgid_t); - snid_ccw.flags = CCW_FLAG_SLI; - - /* - * We now issue a SenseID request. In case of BUSY - * or STATUS PENDING conditions we retry 5 times. - */ - do - { - memset( &devstat, '\0', sizeof( devstat_t) ); - - irq_ret = s390_start_IO( irq, - &snid_ccw, - 0xE2D5C9C4, // == SNID - lpm, // n/a - DOIO_WAIT_FOR_INTERRUPT - | DOIO_VALID_LPM ); - - if ( !irq_ret ) - { - if ( devstat.flag & DEVSTAT_STATUS_PENDING ) - { -#if CONFIG_DEBUG_IO - printk( "SNID - Device %04X " - "on Subchannel %04X " - "reports pending status, " - "retry : %d\n", - ioinfo[irq]->schib.pmcw.dev, - irq, - retry); -#endif - } /* endif */ - - if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL ) - { - /* - * If the device doesn't support the - * Sense Path Group ID command - * further retries wouldn't help ... - */ - if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT ) - { - retry = 0; - irq_ret = -EOPNOTSUPP; - } -#if CONFIG_DEBUG_IO - else - { - printk( "SNID - device %04X," - " unit check," - " retry %d, cnt %02d," - " sns :" - " %02X%02X%02X%02X %02X%02X%02X%02X ...\n", - ioinfo[irq]->schib.pmcw.dev, - retry, - devstat.scnt, - devstat.ii.sense.data[0], - devstat.ii.sense.data[1], - devstat.ii.sense.data[2], - devstat.ii.sense.data[3], - devstat.ii.sense.data[4], - devstat.ii.sense.data[5], - devstat.ii.sense.data[6], - devstat.ii.sense.data[7]); - - } /* endif */ -#endif - } - else if ( devstat.flag & DEVSTAT_NOT_OPER ) - { - printk( "SNID - Device %04X " - "on Subchannel %04X " - "became 'not operational'\n", - ioinfo[irq]->schib.pmcw.dev, - irq); - - retry = 0; - - } /* endif */ - } - else if ( irq_ret != -ENODEV ) - { - retry--; - } - else - { - retry = 0; - - } /* endif */ - - } while ( retry > 0 ); - - s390irq_spin_unlock( irq); - - /* - * If we installed the irq action handler we have to - * release it too. - */ - if ( inlreq ) - free_irq( irq, &devstat); - - } /* endif */ - - return( irq_ret ); -} - - -void do_crw_pending( void ) -{ - return; -} - - -/* added by Holger Smolinski for reipl support in reipl.S */ -void -reipl ( int sch ) -{ - int i; - - for ( i = 0; i < highest_subchannel; i ++ ) { - free_irq ( i, (void*)REIPL_DEVID_MAGIC ); - } - do_reipl( 0x10000 | sch ); -} - diff --git a/arch/s390/kernel/s390mach.c b/arch/s390/kernel/s390mach.c deleted file mode 100644 index 750e50c30..000000000 --- a/arch/s390/kernel/s390mach.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * arch/s390/kernel/s390mach.c - * S/390 machine check handler, - * currently only channel-reports are supported - * - * S390 version - * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Ingo Adlung (adlung@de.ibm.com) - */ - -#include <linux/init.h> - -#include <asm/irq.h> -#include <asm/lowcore.h> -#include <asm/semaphore.h> -#include <asm/s390io.h> -#include <asm/s390dyn.h> -#include <asm/s390mach.h> - -#define S390_MACHCHK_DEBUG - -static mchchk_queue_element_t *mchchk_queue_head = NULL; -static mchchk_queue_element_t *mchchk_queue_tail = NULL; -static mchchk_queue_element_t *mchchk_queue_free = NULL; -static spinlock_t mchchk_queue_lock; -static struct semaphore s_sem[2]; - -// -// initialize machine check handling -// -void s390_init_machine_check( void ) -{ - init_MUTEX_LOCKED( &s_sem[0] ); - init_MUTEX_LOCKED( &s_sem[1] ); - -#if 0 - // - // fix me ! initialize a machine check queue with 100 elements - // -#ifdef S390_MACHCHK_DEBUG - printk( "init_mach : starting kernel thread\n"); -#endif - - kernel_thread( s390_machine_check_handler, s_sem, 0); - - // - // wait for the machine check handler to be ready - // -#ifdef S390_MACHCHK_DEBUG - printk( "init_mach : waiting for kernel thread\n"); -#endif - - down( &sem[0]); - -#ifdef S390_MACHCHK_DEBUG - printk( "init_mach : kernel thread ready\n"); -#endif - - // - // fix me ! we have to initialize CR14 to allow for CRW pending - // conditions - - // - // fix me ! enable machine checks in the PSW - // -#endif - return; -} - -// -// machine check pre-processor -// -void __init s390_do_machine_check( void ) -{ - // fix me ! we have to check for machine check and - // post the handler eventually - - return; -} - -// -// machine check handler -// -static void __init s390_machine_check_handler( struct semaphore *sem ) -{ -#ifdef S390_MACHCHK_DEBUG - printk( "mach_handler : kernel thread up\n"); -#endif - - up( &sem[0] ); - -#ifdef S390_MACHCHK_DEBUG - printk( "mach_handler : kernel thread ready\n"); -#endif - - do { - -#ifdef S390_MACHCHK_DEBUG - printk( "mach_handler : waiting for wakeup\n"); -#endif - - down_interruptible( &sem[1] ); -#ifdef S390_MACHCHK_DEBUG - printk( "mach_handler : wakeup\n"); -#endif - - break; // fix me ! unconditional surrender ... - - // fix me ! check for machine checks and - // call do_crw_pending() eventually - - } while (1); - - return; -} - -mchchk_queue_element_t *s390_get_mchchk( void ) -{ - unsigned long flags; - mchchk_queue_element_t *qe; - - spin_lock_irqsave( &mchchk_queue_lock, flags ); - - // fix me ! dequeue first element if available - qe = NULL; - - spin_unlock_irqrestore( &mchchk_queue_lock, flags ); - - return qe; -} - -void s390_free_mchchk( mchchk_queue_element_t *mchchk ) -{ - unsigned long flags; - - if ( mchchk != NULL) - { - spin_lock_irqsave( &mchchk_queue_lock, flags ); - - mchchk->next = mchchk_queue_free; - - if ( mchchk_queue_free != NULL ) - { - mchchk_queue_free->prev = mchchk; - - } /* endif */ - - mchchk->prev = NULL; - mchchk_queue_free = mchchk; - - spin_unlock_irqrestore( &mchchk_queue_lock, flags ); - - } /* endif */ - - return; -} - diff --git a/arch/s390/kernel/semaphore.c b/arch/s390/kernel/semaphore.c index a0a434581..8af6d8277 100644 --- a/arch/s390/kernel/semaphore.c +++ b/arch/s390/kernel/semaphore.c @@ -2,7 +2,7 @@ * linux/arch/S390/kernel/semaphore.c * * S390 version - * Copyright (C) 1998 IBM Corporation + * Copyright (C) 1998-2000 IBM Corporation * Author(s): Martin Schwidefsky * * Derived from "linux/arch/i386/kernel/semaphore.c diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 109af4e76..628d7bcf7 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -21,7 +21,7 @@ #include <linux/stddef.h> #include <linux/unistd.h> #include <linux/ptrace.h> -#include <linux/malloc.h> +#include <linux/slab.h> #include <linux/user.h> #include <linux/a.out.h> #include <linux/tty.h> @@ -45,6 +45,7 @@ __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 */ /* * Setup options @@ -80,6 +81,7 @@ static struct resource data_resource = { "Kernel data", 0, 0 }; void __init cpu_init (void) { int nr = smp_processor_id(); + int addr = hard_smp_processor_id(); if (test_and_set_bit(nr,&cpu_initialized)) { printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr); @@ -91,7 +93,7 @@ void __init cpu_init (void) * Store processor id in lowcore (used e.g. in timer_interrupt) */ asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id)); - S390_lowcore.cpu_data.cpu_addr = hard_smp_processor_id(); + S390_lowcore.cpu_data.cpu_addr = addr; S390_lowcore.cpu_data.cpu_nr = nr; /* @@ -158,33 +160,18 @@ void machine_halt(void) { if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) cpcmd(vmhalt_cmd, NULL, 0); - disabled_wait(0); + signal_processor(smp_processor_id(), sigp_stop_and_store_status); } void machine_power_off(void) { if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) cpcmd(vmpoff_cmd, NULL, 0); - disabled_wait(0); + signal_processor(smp_processor_id(), sigp_stop_and_store_status); } #endif /* - * Waits for 'delay' microseconds using the tod clock - */ -void tod_wait(unsigned long delay) -{ - uint64_t start_cc, end_cc; - - if (delay == 0) - return; - asm volatile ("STCK %0" : "=m" (start_cc)); - do { - asm volatile ("STCK %0" : "=m" (end_cc)); - } while (((end_cc - start_cc)/4096) < delay); -} - -/* * Setup function called from init/main.c just after the banner * was printed. */ @@ -192,12 +179,11 @@ void __init setup_arch(char **cmdline_p) { unsigned long bootmap_size; unsigned long memory_start, memory_end; - char c = ' ', *to = command_line, *from = COMMAND_LINE; + char c = ' ', cn, *to = command_line, *from = COMMAND_LINE; struct resource *res; unsigned long start_pfn, end_pfn; static unsigned int smptrap=0; unsigned long delay = 0; - int len = 0; if (smptrap) return; @@ -210,6 +196,7 @@ void __init setup_arch(char **cmdline_p) */ cpu_init(); boot_cpu_addr = S390_lowcore.cpu_data.cpu_addr; + __cpu_logical_map[0] = boot_cpu_addr; /* * print what head.S has found out about the machine @@ -227,10 +214,15 @@ void __init setup_arch(char **cmdline_p) rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); #endif - /* nasty stuff with PARMAREAs. we use head.S or parameterline - if (!MOUNT_ROOT_RDONLY) - root_mountflags &= ~MS_RDONLY; - */ + memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ + memory_end = MEMORY_SIZE; + /* + * We need some free virtual space to be able to do vmalloc. + * On a machine with 2GB memory we make sure that we have at + * least 128 MB free space for vmalloc. + */ + if (memory_end > 1920*1024*1024) + memory_end = 1920*1024*1024; memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ memory_end = MEMORY_SIZE; /* detected in head.s */ init_mm.start_code = PAGE_OFFSET; @@ -252,7 +244,6 @@ void __init setup_arch(char **cmdline_p) * "mem=XXX[kKmM]" sets memsize */ if (c == ' ' && strncmp(from, "mem=", 4) == 0) { - if (to != command_line) to--; memory_end = simple_strtoul(from+4, &from, 0); if ( *from == 'K' || *from == 'k' ) { memory_end = memory_end << 10; @@ -275,16 +266,22 @@ void __init setup_arch(char **cmdline_p) delay = delay*60*1000000; from++; } - /* now wait for the requestion amount of time */ - tod_wait(delay); + /* now wait for the requestedn amount of time */ + udelay(delay); } - c = *(from++); - if (!c) + cn = *(from++); + if (!cn) break; - if (COMMAND_LINE_SIZE <= ++len) + if (cn == '\n') + cn = ' '; /* replace newlines with space */ + if (cn == ' ' && c == ' ') + continue; /* remove additional spaces */ + c = cn; + if (to - command_line >= COMMAND_LINE_SIZE) break; *(to++) = c; } + if (c == ' ' && to > command_line) to--; *to = '\0'; *cmdline_p = command_line; @@ -317,7 +314,7 @@ void __init setup_arch(char **cmdline_p) paging_init(); #ifdef CONFIG_BLK_DEV_INITRD if (INITRD_START) { - if (INITRD_START + INITRD_SIZE < memory_end) { + if (INITRD_START + INITRD_SIZE <= memory_end) { reserve_bootmem(INITRD_START, INITRD_SIZE); initrd_start = INITRD_START; initrd_end = initrd_start + INITRD_SIZE; @@ -368,8 +365,8 @@ int get_cpuinfo(char * buffer) p += sprintf(p,"vendor_id : IBM/S390\n" "# processors : %i\n" "bogomips per cpu: %lu.%02lu\n", - smp_num_cpus, loops_per_sec/500000, - (loops_per_sec/5000)%100); + smp_num_cpus, loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ))%100); for (i = 0; i < smp_num_cpus; i++) { cpuinfo = &safe_get_cpu_lowcore(i).cpu_data; p += sprintf(p,"processor %i: " diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 7809a4a2b..de05ec764 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -2,7 +2,7 @@ * arch/s390/kernel/signal.c * * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) * * Based on Intel version @@ -37,7 +37,7 @@ #define SIGFRAME_COMMON \ __u8 callee_used_stack[__SIGNAL_FRAMESIZE]; \ struct sigcontext sc; \ -sigregs sregs; \ +_sigregs sregs; \ __u8 retcode[S390_SYSCALL_SIZE]; typedef struct @@ -54,6 +54,41 @@ typedef struct asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); +int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) +{ + if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) + return -EFAULT; + if (from->si_code < 0) + return __copy_to_user(to, from, sizeof(siginfo_t)); + else { + int err; + + /* If you change siginfo_t structure, please be sure + this code is fixed accordingly. + It should never copy any pad contained in the structure + to avoid security leaks, but must copy the generic + 3 ints plus the relevant union member. */ + err = __put_user(from->si_signo, &to->si_signo); + err |= __put_user(from->si_errno, &to->si_errno); + err |= __put_user((short)from->si_code, &to->si_code); + /* First 32bits of unions are always present. */ + err |= __put_user(from->si_pid, &to->si_pid); + switch (from->si_code >> 16) { + case __SI_FAULT >> 16: + break; + case __SI_CHLD >> 16: + err |= __put_user(from->si_utime, &to->si_utime); + err |= __put_user(from->si_stime, &to->si_stime); + err |= __put_user(from->si_status, &to->si_status); + default: + err |= __put_user(from->si_uid, &to->si_uid); + break; + /* case __SI_RT: This is not generated by the kernel as of now. */ + } + return err; + } +} + /* * Atomically swap in the new signal mask, and wait for a signal. */ @@ -71,7 +106,7 @@ sys_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t ma regs->gprs[2] = -EINTR; while (1) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule(); if (do_signal(regs, &saveset)) return -EINTR; @@ -99,7 +134,7 @@ sys_rt_sigsuspend(struct pt_regs * regs,sigset_t *unewset, size_t sigsetsize) regs->gprs[2] = -EINTR; while (1) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule(); if (do_signal(regs, &saveset)) return -EINTR; @@ -139,16 +174,15 @@ sys_sigaction(int sig, const struct old_sigaction *act, } asmlinkage int -sys_sigaltstack(const stack_t *uss, stack_t *uoss) +sys_sigaltstack(const stack_t *uss, stack_t *uoss, struct pt_regs *regs) { - struct pt_regs *regs = (struct pt_regs *) &uss; return do_sigaltstack(uss, uoss, regs->gprs[15]); } -static int save_sigregs(struct pt_regs *regs,sigregs *sregs) +static int save_sigregs(struct pt_regs *regs,_sigregs *sregs) { int err; s390_fp_regs fpregs; @@ -163,7 +197,7 @@ static int save_sigregs(struct pt_regs *regs,sigregs *sregs) } -static int restore_sigregs(struct pt_regs *regs,sigregs *sregs) +static int restore_sigregs(struct pt_regs *regs,_sigregs *sregs) { int err; s390_fp_regs fpregs; @@ -185,13 +219,13 @@ static int restore_sigregs(struct pt_regs *regs,sigregs *sregs) static int restore_sigcontext(struct sigcontext *sc, pt_regs *regs, - sigregs *sregs,sigset_t *set) + _sigregs *sregs,sigset_t *set) { unsigned int err; err=restore_sigregs(regs,sregs); if(!err) - err=__copy_from_user(&set->sig,&sc->oldmask,SIGMASK_COPY_SIZE); + err=__copy_from_user(&set->sig,&sc->oldmask,_SIGMASK_COPY_SIZE); return(err); } @@ -227,15 +261,12 @@ badframe: asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) { rt_sigframe *frame = (rt_sigframe *)regs->gprs[15]; - stack_t st; if (sigreturn_common(regs,sizeof(rt_sigframe))) goto badframe; - if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st))) - goto badframe; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ - do_sigaltstack(&st, NULL, regs->gprs[15]); + do_sigaltstack(&frame->uc.uc_stack, NULL, regs->gprs[15]); return regs->gprs[2]; badframe: @@ -290,7 +321,7 @@ static void *setup_frame_common(int sig, struct k_sigaction *ka, err=__put_user(&frame->sregs,&frame->sc.sregs); if(!err) - err=__copy_to_user(&frame->sc.oldmask,&set->sig,SIGMASK_COPY_SIZE); + err=__copy_to_user(&frame->sc.oldmask,&set->sig,_SIGMASK_COPY_SIZE); if(!err) { regs->gprs[2]=(current->exec_domain @@ -316,14 +347,17 @@ static void *setup_frame_common(int sig, struct k_sigaction *ka, static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) { + sigframe *frame; - if(!setup_frame_common(sig,ka,set,regs,sizeof(sigframe), - (S390_SYSCALL_OPCODE|__NR_sigreturn))) + if((frame=setup_frame_common(sig,ka,set,regs,sizeof(sigframe), + (S390_SYSCALL_OPCODE|__NR_sigreturn)))==0) goto give_sigsegv; #if DEBUG_SIG printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n", current->comm, current->pid, frame, regs->eip, frame->pretcode); #endif + /* Martin wants this for pthreads */ + regs->gprs[3] = (addr_t)&frame->sc; return; give_sigsegv: @@ -343,7 +377,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, (S390_SYSCALL_OPCODE|__NR_rt_sigreturn)))==0) goto give_sigsegv; - err = __copy_to_user(&frame->info, info, sizeof(*info)); + err = copy_siginfo_to_user(&frame->info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); @@ -352,8 +386,9 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, err |= __put_user(sas_ss_flags(orig_sp), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); - regs->gprs[3] = (u32)&frame->info; - regs->gprs[4] = (u32)&frame->uc; + err |= __put_user(&frame->sc,&frame->uc.sc); + regs->gprs[3] = (addr_t)&frame->info; + regs->gprs[4] = (addr_t)&frame->uc; if (err) goto give_sigsegv; @@ -452,10 +487,10 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) if (!signr) break; - if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; - current->state = TASK_STOPPED; + set_current_state(TASK_STOPPED); notify_parent(current, SIGCHLD); schedule(); @@ -511,7 +546,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) /* FALLTHRU */ case SIGSTOP: - current->state = TASK_STOPPED; + set_current_state(TASK_STOPPED); current->exit_code = signr; if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); @@ -540,7 +575,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset) } /* Did we come from a system call? */ - if ( regs->trap == 0x20 /* System Call! */ ) { + if ( regs->trap == __LC_SVC_OLD_PSW /* System Call! */ ) { /* Restart the system call - no handlers present */ if (regs->gprs[2] == -ERESTARTNOHAND || regs->gprs[2] == -ERESTARTSYS || diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 6cf2e6918..4b15b5501 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -32,16 +32,15 @@ #include <asm/sigp.h> #include <asm/pgalloc.h> #include <asm/irq.h> +#include <asm/s390_ext.h> #include "cpcmd.h" /* prototypes */ -extern void update_one_process( struct task_struct *p, - unsigned long ticks, unsigned long user, - unsigned long system, int cpu); extern int cpu_idle(void * unused); extern __u16 boot_cpu_addr; +extern volatile int __cpu_logical_map[]; /* * An array with a pointer the lowcore of every CPU. @@ -52,10 +51,8 @@ struct _lowcore *lowcore_ptr[NR_CPUS]; unsigned int prof_multiplier[NR_CPUS]; unsigned int prof_old_multiplier[NR_CPUS]; unsigned int prof_counter[NR_CPUS]; -volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ cycles_t cacheflush_time=0; int smp_threads_ready=0; /* Set when the idlers are all forked. */ -unsigned long ipi_count=0; /* Number of IPIs delivered. */ static atomic_t smp_commenced = ATOMIC_INIT(0); spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; @@ -104,7 +101,7 @@ void do_machine_restart(void) void machine_restart(char * __unused) { if (smp_processor_id() != 0) { - smp_ext_call_async(0, ec_restart); + smp_ext_bitcall(0, ec_restart); for (;;); } else do_machine_restart(); @@ -115,13 +112,13 @@ void do_machine_halt(void) smp_send_stop(); if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) cpcmd(vmhalt_cmd, NULL, 0); - disabled_wait(0); + signal_processor(smp_processor_id(), sigp_stop_and_store_status); } void machine_halt(void) { if (smp_processor_id() != 0) { - smp_ext_call_async(0, ec_halt); + smp_ext_bitcall(0, ec_halt); for (;;); } else do_machine_halt(); @@ -132,13 +129,13 @@ void do_machine_power_off(void) smp_send_stop(); if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) cpcmd(vmpoff_cmd, NULL, 0); - disabled_wait(0); + signal_processor(smp_processor_id(), sigp_stop_and_store_status); } void machine_power_off(void) { if (smp_processor_id() != 0) { - smp_ext_call_async(0, ec_power_off); + smp_ext_bitcall(0, ec_power_off); for (;;); } else do_machine_power_off(); @@ -149,7 +146,7 @@ void machine_power_off(void) * cpus are handled. */ -void do_ext_call_interrupt(__u16 source_cpu_addr) +void do_ext_call_interrupt(struct pt_regs *regs, __u16 code) { ec_ext_call *ec, *next; int bits; @@ -172,6 +169,8 @@ void do_ext_call_interrupt(__u16 source_cpu_addr) do_machine_halt(); if (test_bit(ec_power_off, &bits)) do_machine_power_off(); + if (test_bit(ec_ptlb, &bits)) + local_flush_tlb(); /* * Handle external call commands with a parameter area @@ -184,7 +183,7 @@ void do_ext_call_interrupt(__u16 source_cpu_addr) return; /* no command signals */ /* Make a fifo out of the lifo */ - next = ec; + next = ec->next; ec->next = NULL; while (next != NULL) { ec_ext_call *tmp = next->next; @@ -196,61 +195,21 @@ void do_ext_call_interrupt(__u16 source_cpu_addr) /* Execute every sigp command on the queue */ while (ec != NULL) { switch (ec->cmd) { - case ec_get_ctl: { - ec_creg_parms *pp; - pp = (ec_creg_parms *) ec->parms; + case ec_callback_async: { + void (*func)(void *info); + void *info; + + func = ec->func; + info = ec->info; atomic_set(&ec->status,ec_executing); - asm volatile ( - " bras 1,0f\n" - " stctl 0,0,0(%0)\n" - "0: ex %1,0(1)\n" - : : "a" (pp->cregs+pp->start_ctl), - "a" ((pp->start_ctl<<4) + pp->end_ctl) - : "memory", "1" ); - atomic_set(&ec->status,ec_done); + (func)(info); return; } - case ec_set_ctl: { - ec_creg_parms *pp; - pp = (ec_creg_parms *) ec->parms; + case ec_callback_sync: atomic_set(&ec->status,ec_executing); - asm volatile ( - " bras 1,0f\n" - " lctl 0,0,0(%0)\n" - "0: ex %1,0(1)\n" - : : "a" (pp->cregs+pp->start_ctl), - "a" ((pp->start_ctl<<4) + pp->end_ctl) - : "memory", "1" ); + (ec->func)(ec->info); atomic_set(&ec->status,ec_done); return; - } - case ec_set_ctl_masked: { - ec_creg_mask_parms *pp; - u32 cregs[16]; - int i; - - pp = (ec_creg_mask_parms *) ec->parms; - atomic_set(&ec->status,ec_executing); - asm volatile ( - " bras 1,0f\n" - " stctl 0,0,0(%0)\n" - "0: ex %1,0(1)\n" - : : "a" (cregs+pp->start_ctl), - "a" ((pp->start_ctl<<4) + pp->end_ctl) - : "memory", "1" ); - for (i = pp->start_ctl; i <= pp->end_ctl; i++) - cregs[i] = (cregs[i] & pp->andvals[i]) - | pp->orvals[i]; - asm volatile ( - " bras 1,0f\n" - " lctl 0,0,0(%0)\n" - "0: ex %1,0(1)\n" - : : "a" (cregs+pp->start_ctl), - "a" ((pp->start_ctl<<4) + pp->end_ctl) - : "memory", "1" ); - atomic_set(&ec->status,ec_done); - return; - } default: } ec = ec->next; @@ -258,17 +217,19 @@ void do_ext_call_interrupt(__u16 source_cpu_addr) } /* - * Send an external call sigp to another cpu and wait for its completion. + * Send a callback sigp to another cpu. */ -sigp_ccode smp_ext_call_sync(int cpu, ec_cmd_sig cmd, void *parms) +sigp_ccode +smp_ext_call(int cpu, void (*func)(void *info), void *info, int wait) { struct _lowcore *lowcore = &get_cpu_lowcore(cpu); sigp_ccode ccode; ec_ext_call ec; - ec.cmd = cmd; + ec.cmd = wait ? ec_callback_sync : ec_callback_async; atomic_set(&ec.status, ec_pending); - ec.parms = parms; + ec.func = func; + ec.info = info; do { ec.next = (ec_ext_call*) atomic_read(&lowcore->ext_call_queue); } while (atomic_compare_and_swap((int) ec.next, (int)(&ec), @@ -288,34 +249,15 @@ sigp_ccode smp_ext_call_sync(int cpu, ec_cmd_sig cmd, void *parms) if (ccode != sigp_not_operational) /* wait for completion, FIXME: possible seed of a deadlock */ - while (atomic_read(&ec.status) != ec_done); + while (atomic_read(&ec.status) != (wait?ec_done:ec_executing)); return ccode; } /* - * Send an external call sigp to another cpu and return without waiting - * for its completion. Currently we do not support parameters with - * asynchronous sigps. + * Send a callback sigp to every other cpu in the system. */ -sigp_ccode smp_ext_call_async(int cpu, ec_bit_sig sig) -{ - struct _lowcore *lowcore = &get_cpu_lowcore(cpu); - sigp_ccode ccode; - - /* - * Set signaling bit in lowcore of target cpu and kick it - */ - atomic_set_mask(1<<sig, &lowcore->ext_call_fast); - ccode = signal_processor(cpu, sigp_external_call); - return ccode; -} - -/* - * Send an external call sigp to every other cpu in the system and - * wait for the completion of the sigps. - */ -void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms) +void smp_ext_call_others(void (*func)(void *info), void *info, int wait) { struct _lowcore *lowcore; ec_ext_call ec[NR_CPUS]; @@ -326,9 +268,10 @@ void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms) if (smp_processor_id() == i) continue; lowcore = &get_cpu_lowcore(i); - ec[i].cmd = cmd; - atomic_set(&ec[i].status, ec_pending); - ec[i].parms = parms; + ec[i].cmd = wait ? ec_callback_sync : ec_callback_async; + atomic_set(&ec[i].status, ec_pending); + ec[i].func = func; + ec[i].info = info; do { ec[i].next = (ec_ext_call *) atomic_read(&lowcore->ext_call_queue); @@ -341,16 +284,33 @@ void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms) for (i = 0; i < smp_num_cpus; i++) { if (smp_processor_id() == i) continue; - while (atomic_read(&ec[i].status) != ec_done); + while (atomic_read(&ec[i].status) != + (wait ? ec_done:ec_executing)); } } /* + * Send an external call sigp to another cpu and return without waiting + * for its completion. + */ +sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig) +{ + struct _lowcore *lowcore = &get_cpu_lowcore(cpu); + sigp_ccode ccode; + + /* + * Set signaling bit in lowcore of target cpu and kick it + */ + atomic_set_mask(1<<sig, &lowcore->ext_call_fast); + ccode = signal_processor(cpu, sigp_external_call); + return ccode; +} + +/* * Send an external call sigp to every other cpu in the system and - * return without waiting for the completion of the sigps. Currently - * we do not support parameters with asynchronous sigps. + * return without waiting for its completion. */ -void smp_ext_call_async_others(ec_bit_sig sig) +void smp_ext_bitcall_others(ec_bit_sig sig) { struct _lowcore *lowcore; sigp_ccode ccode; @@ -420,7 +380,46 @@ int smp_signal_others(sigp_order_code order_code, u32 parameter, void smp_send_stop(void) { - smp_signal_others(sigp_stop, 0, 1, NULL); + int i; + u32 dummy; + unsigned long low_core_addr; + + /* write magic number to zero page (absolute 0) */ + + get_cpu_lowcore(smp_processor_id()).panic_magic = __PANIC_MAGIC; + + /* stop all processors */ + + smp_signal_others(sigp_stop, 0, TRUE, NULL); + + /* store status of all processors in their lowcores (real 0) */ + + for (i = 0; i < smp_num_cpus; i++) { + if (smp_processor_id() != i) { + int ccode; + low_core_addr = (unsigned long)&get_cpu_lowcore(i); + do { + ccode = signal_processor_ps( + &dummy, + low_core_addr, + i, + sigp_store_status_at_address); + } while(ccode == sigp_busy); + } + } +} + +/* + * this function sends a 'purge tlb' signal to another CPU. + */ +void smp_ptlb_callback(void *info) +{ + local_flush_tlb(); +} + +void smp_ptlb_all(void) +{ + smp_ext_call_others(smp_ptlb_callback, NULL, 1); } /* @@ -431,7 +430,44 @@ void smp_send_stop(void) void smp_send_reschedule(int cpu) { - smp_ext_call_async(cpu, ec_schedule); + smp_ext_bitcall(cpu, ec_schedule); +} + +/* + * parameter area for the set/clear control bit callbacks + */ +typedef struct +{ + __u16 start_ctl; + __u16 end_ctl; + __u32 orvals[16]; + __u32 andvals[16]; +} ec_creg_mask_parms; + +/* + * callback for setting/clearing control bits + */ +void smp_ctl_bit_callback(void *info) { + ec_creg_mask_parms *pp; + u32 cregs[16]; + int i; + + pp = (ec_creg_mask_parms *) info; + asm volatile (" bras 1,0f\n" + " stctl 0,0,0(%0)\n" + "0: ex %1,0(1)\n" + : : "a" (cregs+pp->start_ctl), + "a" ((pp->start_ctl<<4) + pp->end_ctl) + : "memory", "1" ); + for (i = pp->start_ctl; i <= pp->end_ctl; i++) + cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i]; + asm volatile (" bras 1,0f\n" + " lctl 0,0,0(%0)\n" + "0: ex %1,0(1)\n" + : : "a" (cregs+pp->start_ctl), + "a" ((pp->start_ctl<<4) + pp->end_ctl) + : "memory", "1" ); + return; } /* @@ -445,7 +481,7 @@ void smp_ctl_set_bit(int cr, int bit) { parms.end_ctl = cr; parms.orvals[cr] = 1 << bit; parms.andvals[cr] = 0xFFFFFFFF; - smp_ext_call_sync_others(ec_set_ctl_masked,&parms); + smp_ext_call_others(smp_ctl_bit_callback, &parms, 1); } __ctl_set_bit(cr, bit); } @@ -461,11 +497,35 @@ void smp_ctl_clear_bit(int cr, int bit) { parms.end_ctl = cr; parms.orvals[cr] = 0x00000000; parms.andvals[cr] = ~(1 << bit); - smp_ext_call_sync_others(ec_set_ctl_masked,&parms); + smp_ext_call_others(smp_ctl_bit_callback, &parms, 1); } __ctl_clear_bit(cr, bit); } +/* + * Call a function on all other processors + */ + +int +smp_call_function(void (*func)(void *info), void *info, int retry, int wait) +/* + * [SUMMARY] Run a function on all other CPUs. + * <func> The function to run. This must be fast and non-blocking. + * <info> An arbitrary pointer to pass to the function. + * <retry> currently unused. + * <wait> If true, wait (atomically) until function has completed on other CPUs. + * [RETURNS] 0 on success, else a negative status code. Does not return until + * remote CPUs are nearly ready to execute <<func>> or are or have executed. + * + * You must not call this function with disabled interrupts or from a + * hardware interrupt handler, you may call it from a bottom half handler. + */ +{ + if (atomic_read(&smp_commenced) != 0) + smp_ext_call_others(func, info, 1); + (func)(info); + return 0; +} /* * Lets check how many CPUs we have. @@ -475,7 +535,6 @@ void smp_count_cpus(void) { int curr_cpu; - __cpu_logical_map[0] = boot_cpu_addr; current->processor = 0; smp_num_cpus = 1; for (curr_cpu = 0; @@ -527,7 +586,7 @@ static int __init fork_by_hand(void) struct pt_regs regs; /* don't care about the psw and regs settings since we'll never reschedule the forked task. */ - memset(®s,sizeof(pt_regs),0); + memset(®s,0,sizeof(pt_regs)); return do_fork(CLONE_VM|CLONE_PID, 0, ®s, 0); } @@ -594,7 +653,10 @@ void __init smp_boot_cpus(void) struct _lowcore *curr_lowcore; sigp_ccode ccode; int i; - + + /* request the 0x1202 external interrupt */ + if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0) + panic("Couldn't request external interrupt 0x1202"); smp_count_cpus(); memset(lowcore_ptr,0,sizeof(lowcore_ptr)); @@ -705,24 +767,7 @@ void smp_local_timer_interrupt(struct pt_regs * regs) */ irq_enter(cpu, 0); - update_one_process(p, 1, user, system, cpu); - if (p->pid) { - p->counter -= 1; - if (p->counter <= 0) { - p->counter = 0; - p->need_resched = 1; - } - if (p->nice > 0) { - kstat.cpu_nice += user; - kstat.per_cpu_nice[cpu] += user; - } else { - kstat.cpu_user += user; - kstat.per_cpu_user[cpu] += user; - } - kstat.cpu_system += system; - kstat.per_cpu_system[cpu] += system; - - } + update_process_times(user); irq_exit(cpu, 0); } } diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c index b00d88a62..cc7700864 100644 --- a/arch/s390/kernel/sys_s390.c +++ b/arch/s390/kernel/sys_s390.c @@ -71,18 +71,10 @@ out: return error; } -/* FIXME: 6 parameters is one too much ... */ -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff) -{ - return do_mmap2(addr, len, prot, flags, fd, pgoff); -} - /* * Perform the select(nd, in, out, ex, tv) and mmap() system - * calls. Linux/i386 didn't use to be able to handle more than - * 4 system call parameters, so these system calls used a memory + * calls. Linux for S/390 isn't able to handle more than 5 + * system call parameters, so these system calls used a memory * block for parameter passing.. */ @@ -95,6 +87,18 @@ struct mmap_arg_struct { unsigned long offset; }; +asmlinkage long sys_mmap2(struct mmap_arg_struct *arg) +{ + struct mmap_arg_struct a; + int error = -EFAULT; + + if (copy_from_user(&a, arg, sizeof(a))) + goto out; + error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); +out: + return error; +} + asmlinkage int old_mmap(struct mmap_arg_struct *arg) { struct mmap_arg_struct a; @@ -239,7 +243,7 @@ asmlinkage int sys_olduname(struct oldold_utsname * name) asmlinkage int sys_pause(void) { - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); schedule(); return -ERESTARTNOHAND; } diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 8cd84ee54..f4bde27b3 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -11,7 +11,6 @@ * Copyright (C) 1991, 1992, 1995 Linus Torvalds */ -#include <linux/config.h> #include <linux/errno.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -27,15 +26,14 @@ #include <asm/uaccess.h> #include <asm/delay.h> +#include <asm/s390_ext.h> -#include <linux/mc146818rtc.h> #include <linux/timex.h> +#include <linux/config.h> #include <asm/irq.h> -extern volatile unsigned long lost_ticks; - /* change this if you have some constant time drift */ #define USECS_PER_JIFFY ((signed long)1000000/HZ) #define CLK_TICKS_PER_JIFFY ((signed long)USECS_PER_JIFFY<<12) @@ -45,6 +43,7 @@ extern volatile unsigned long lost_ticks; static uint64_t init_timer_cc, last_timer_cc; extern rwlock_t xtime_lock; +extern unsigned long wall_jiffies; void tod_to_timeval(uint64_t todval, struct timeval *xtime) { @@ -94,9 +93,9 @@ unsigned long do_gettimeoffset(void) */ void do_gettimeofday(struct timeval *tv) { - extern volatile unsigned long lost_ticks; unsigned long flags; unsigned long usec, sec; + unsigned long lost_ticks = jiffies - wall_jiffies; read_lock_irqsave(&xtime_lock, flags); usec = do_gettimeoffset(); @@ -149,7 +148,7 @@ void do_settimeofday(struct timeval *tv) extern __u16 boot_cpu_addr; #endif -void do_timer_interrupt(struct pt_regs *regs,int error_code) +void do_timer_interrupt(struct pt_regs *regs, __u16 error_code) { unsigned long flags; @@ -242,6 +241,9 @@ void __init time_init(void) printk("time_init: TOD clock stopped/non-operational\n"); break; } + /* request the 0x1004 external interrupt */ + if (register_external_interrupt(0x1004, do_timer_interrupt) != 0) + panic("Couldn't request external interrupts 0x1004"); init_100hz_timer(); init_timer_cc = S390_lowcore.jiffy_timer_cc; init_timer_cc -= 0x8126d60e46000000LL - diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 4af4f6565..fc774a7db 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -42,122 +42,15 @@ extern void handle_per_exception(struct pt_regs *regs); typedef void pgm_check_handler_t(struct pt_regs *, long); pgm_check_handler_t *pgm_check_table[128]; -extern pgm_check_handler_t default_trap_handler; -extern pgm_check_handler_t do_page_fault; - -asmlinkage int system_call(void); - -#define DO_ERROR(trapnr, signr, str, name, tsk) \ -asmlinkage void name(struct pt_regs * regs, long error_code) \ -{ \ - tsk->thread.error_code = error_code; \ - tsk->thread.trap_no = trapnr; \ - die_if_no_fixup(str,regs,error_code); \ - force_sig(signr, tsk); \ -} - -/* TODO: define these as 'pgm_check_handler_t xxx;' -asmlinkage void divide_error(void); -asmlinkage void debug(void); -asmlinkage void nmi(void); -asmlinkage void int3(void); -asmlinkage void overflow(void); -asmlinkage void bounds(void); -asmlinkage void invalid_op(void); -asmlinkage void device_not_available(void); -asmlinkage void double_fault(void); -asmlinkage void coprocessor_segment_overrun(void); -asmlinkage void invalid_TSS(void); -asmlinkage void segment_not_present(void); -asmlinkage void stack_segment(void); -asmlinkage void general_protection(void); -asmlinkage void coprocessor_error(void); -asmlinkage void reserved(void); -asmlinkage void alignment_check(void); -asmlinkage void spurious_interrupt_bug(void); -*/ - -int kstack_depth_to_print = 24; - -/* - * These constants are for searching for possible module text - * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is - * a guess of how much space is likely to be vmalloced. - */ -#define VMALLOC_OFFSET (8*1024*1024) -#define MODULE_RANGE (8*1024*1024) - -void show_crashed_task_info(void) -{ - printk("CPU: %d\n",smp_processor_id()); - printk("Process %s (pid: %d, stackpage=%08X)\n", - current->comm, current->pid, 4096+(addr_t)current); - show_regs(current,NULL,NULL); -} -#if 0 -static void show_registers(struct pt_regs *regs) -{ - printk("CPU: %d\nPSW: %08lx %08lx\n", - smp_processor_id(), (unsigned long) regs->psw.mask, - (unsigned long) regs->psw.addr); - printk("GPRS:\n"); - - printk("%08lx %08lx %08lx %08lx\n", - regs->gprs[0], regs->gprs[1], - regs->gprs[2], regs->gprs[3]); - printk("%08lx %08lx %08lx %08lx\n", - regs->gprs[4], regs->gprs[5], - regs->gprs[6], regs->gprs[7]); - printk("%08lx %08lx %08lx %08lx\n", - regs->gprs[8], regs->gprs[9], - regs->gprs[10], regs->gprs[11]); - printk("%08lx %08lx %08lx %08lx\n", - regs->gprs[12], regs->gprs[13], - regs->gprs[14], regs->gprs[15]); - printk("Process %s (pid: %d, stackpage=%08lx)\nStack: ", - current->comm, current->pid, 4096+(unsigned long)current); -/* - stack = (unsigned long *) esp; - for(i=0; i < kstack_depth_to_print; i++) { - if (((long) stack & 4095) == 0) - break; - if (i && ((i % 8) == 0)) - printk("\n "); - printk("%08lx ", get_seg_long(ss,stack++)); - } - printk("\nCall Trace: "); - stack = (unsigned long *) esp; - i = 1; - module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT); - module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)); - module_end = module_start + MODULE_RANGE; - while (((long) stack & 4095) != 0) { - addr = get_seg_long(ss, stack++); */ - /* - * If the address is either in the text segment of the - * kernel, or in the region which contains vmalloc'ed - * memory, it *may* be the address of a calling - * routine; if so, print it so that someone tracing - * down the cause of the crash will be able to figure - * out the call path that was taken. - */ -/* if (((addr >= (unsigned long) &_stext) && - (addr <= (unsigned long) &_etext)) || - ((addr >= module_start) && (addr <= module_end))) { - if (i && ((i % 8) == 0)) - printk("\n "); - printk("[<%08lx>] ", addr); - i++; - } - } - printk("\nCode: "); - for(i=0;i<20;i++) - printk("%02x ",0xff & get_seg_byte(regs->xcs & 0xffff,(i+(char *)regs->eip))); - printk("\n"); -*/ -} +#ifdef CONFIG_SYSCTL +#ifdef CONFIG_PROCESS_DEBUG +int sysctl_userprocess_debug = 1; +#else +int sysctl_userprocess_debug = 0; +#endif #endif +extern pgm_check_handler_t do_page_fault; spinlock_t die_lock; @@ -166,29 +59,65 @@ void die(const char * str, struct pt_regs * regs, long err) console_verbose(); spin_lock_irq(&die_lock); printk("%s: %04lx\n", str, err & 0xffff); - show_crashed_task_info(); + show_regs(regs); spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } -int check_for_fixup(struct pt_regs * regs) +#define DO_ERROR(signr, str, name) \ +asmlinkage void name(struct pt_regs * regs, long interruption_code) \ +{ \ + do_trap(interruption_code, signr, str, regs, NULL); \ +} + +#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \ +asmlinkage void name(struct pt_regs * regs, long interruption_code) \ +{ \ + siginfo_t info; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void *)siaddr; \ + do_trap(interruption_code, signr, str, regs, &info); \ +} + +static void inline do_trap(long interruption_code, int signr, char *str, + struct pt_regs *regs, siginfo_t *info) { - if (!(regs->psw.mask & PSW_PROBLEM_STATE)) { - unsigned long fixup; - fixup = search_exception_table(regs->psw.addr); - if (fixup) { - regs->psw.addr = fixup; - return 1; + if (regs->psw.mask & PSW_PROBLEM_STATE) { + struct task_struct *tsk = current; + tsk->thread.trap_no = interruption_code; + if (info) + force_sig_info(signr, info, tsk); + else + force_sig(signr, tsk); +#ifndef CONFIG_SYSCTL +#ifdef CONFIG_PROCESS_DEBUG + printk("User process fault: interruption code 0x%lX\n", + interruption_code); + show_regs(regs); +#endif +#else + if (sysctl_userprocess_debug) { + printk("User process fault: interruption code 0x%lX\n", + interruption_code); + show_regs(regs); } - } - return 0; +#endif + } else { + unsigned long fixup = search_exception_table(regs->psw.addr); + if (fixup) + regs->psw.addr = fixup; + else + die(str, regs, interruption_code); + } } int do_debugger_trap(struct pt_regs *regs,int signal) { if(regs->psw.mask&PSW_PROBLEM_STATE) { - if(current->flags & PF_PTRACED) + if(current->ptrace & PT_PTRACED) force_sig(signal,current); else return 1; @@ -207,50 +136,16 @@ int do_debugger_trap(struct pt_regs *regs,int signal) return 0; } -static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err) -{ - if (!(regs->psw.mask & PSW_PROBLEM_STATE)) { - unsigned long fixup; - fixup = search_exception_table(regs->psw.addr); - if (fixup) { - regs->psw.addr = fixup; - return; - } - die(str, regs, err); - } -} - -asmlinkage void default_trap_handler(struct pt_regs * regs, long error_code) -{ - current->thread.error_code = error_code; - current->thread.trap_no = error_code; - die_if_no_fixup("Unknown program exception",regs,error_code); - force_sig(SIGSEGV, current); -} - -DO_ERROR(2, SIGILL, "privileged operation", privileged_op, current) -DO_ERROR(3, SIGILL, "execute exception", execute_exception, current) -DO_ERROR(5, SIGSEGV, "addressing exception", addressing_exception, current) -DO_ERROR(9, SIGFPE, "fixpoint divide exception", divide_exception, current) -DO_ERROR(0x12, SIGILL, "translation exception", translation_exception, current) -DO_ERROR(0x13, SIGILL, "special operand exception", special_op_exception, current) -DO_ERROR(0x15, SIGILL, "operand exception", operand_exception, current) +DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler) +DO_ERROR(SIGILL, "privileged operation", privileged_op) +DO_ERROR(SIGILL, "execute exception", execute_exception) +DO_ERROR(SIGSEGV, "addressing exception", addressing_exception) +DO_ERROR(SIGFPE, "fixpoint divide exception", divide_exception) +DO_ERROR(SIGILL, "translation exception", translation_exception) +DO_ERROR(SIGILL, "special operand exception", special_op_exception) +DO_ERROR(SIGILL, "operand exception", operand_exception) -/* need to define -DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current) -DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current) -DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, last_task_used_math) -DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current) -DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current) -DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current) -DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current) -DO_ERROR(18, SIGSEGV, "reserved", reserved, current) -DO_ERROR(19, SIGSEGV, "cache flush denied", cache_flush_denied, current) -*/ - -#ifdef CONFIG_IEEEFPU_EMULATION - -asmlinkage void illegal_op(struct pt_regs * regs, long error_code) +asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) { __u8 opcode[6]; __u16 *location; @@ -268,6 +163,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long error_code) if(do_debugger_trap(regs,SIGTRAP)) do_sig=1; } +#ifdef CONFIG_IEEEFPU_EMULATION else if (problem_state ) { if (opcode[0] == 0xb3) { @@ -288,18 +184,19 @@ asmlinkage void illegal_op(struct pt_regs * regs, long error_code) do_sig = math_emu_lfpc(opcode, regs); } else do_sig = 1; - } else - do_sig = 1; - if (do_sig) { - current->thread.error_code = error_code; - current->thread.trap_no = 1; - force_sig(SIGILL, current); - die_if_no_fixup("illegal operation", regs, error_code); } +#endif + else + do_sig = 1; + if (do_sig) + do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL); unlock_kernel(); } -asmlinkage void specification_exception(struct pt_regs * regs, long error_code) + + +#ifdef CONFIG_IEEEFPU_EMULATION +asmlinkage void specification_exception(struct pt_regs * regs, long interruption_code) { __u8 opcode[6]; __u16 *location; @@ -311,26 +208,26 @@ asmlinkage void specification_exception(struct pt_regs * regs, long error_code) get_user(*((__u16 *) opcode), location); switch (opcode[0]) { case 0x28: /* LDR Rx,Ry */ - math_emu_ldr(opcode); + do_sig=math_emu_ldr(opcode); break; case 0x38: /* LER Rx,Ry */ - math_emu_ler(opcode); + do_sig=math_emu_ler(opcode); break; case 0x60: /* STD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_std(opcode, regs); + do_sig=math_emu_std(opcode, regs); break; case 0x68: /* LD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_ld(opcode, regs); + do_sig=math_emu_ld(opcode, regs); break; case 0x70: /* STE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_ste(opcode, regs); + do_sig=math_emu_ste(opcode, regs); break; case 0x78: /* LE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_le(opcode, regs); + do_sig=math_emu_le(opcode, regs); break; default: do_sig = 1; @@ -338,47 +235,59 @@ asmlinkage void specification_exception(struct pt_regs * regs, long error_code) } } else do_sig = 1; - if (do_sig) { - current->thread.error_code = error_code; - current->thread.trap_no = 1; - force_sig(SIGILL, current); - die_if_no_fixup("illegal operation", regs, error_code); - } + if (do_sig) + do_trap(interruption_code, SIGILL, "specification exception", regs, NULL); unlock_kernel(); } +#else +DO_ERROR(SIGILL, "specification exception", specification_exception) +#endif -asmlinkage void data_exception(struct pt_regs * regs, long error_code) +asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) { __u8 opcode[6]; __u16 *location; int do_sig = 0; lock_kernel(); - if (regs->psw.mask & 0x00010000L) { - location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc); + if(MACHINE_HAS_IEEE) + { + __asm__ volatile ("stfpc %0\n\t" + : "=m" (current->thread.fp_regs.fpc)); + } + /* Same code should work when we implement fpu emulation */ + /* provided we call data exception from the fpu emulator */ + if(current->thread.fp_regs.fpc&FPC_DXC_MASK) + { + current->thread.ieee_instruction_pointer=(addr_t)location; + force_sig(SIGFPE, current); + } +#ifdef CONFIG_IEEEFPU_EMULATION + else if (regs->psw.mask & 0x00010000L) { get_user(*((__u16 *) opcode), location); switch (opcode[0]) { case 0x28: /* LDR Rx,Ry */ - math_emu_ldr(opcode); + do_sig=math_emu_ldr(opcode); break; case 0x38: /* LER Rx,Ry */ - math_emu_ler(opcode); + do_sig=math_emu_ler(opcode); break; case 0x60: /* STD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_std(opcode, regs); + do_sig=math_emu_std(opcode, regs); break; case 0x68: /* LD R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_ld(opcode, regs); + do_sig=math_emu_ld(opcode, regs); break; case 0x70: /* STE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_ste(opcode, regs); + do_sig=math_emu_ste(opcode, regs); break; case 0x78: /* LE R,D(X,B) */ get_user(*((__u16 *) (opcode+2)), location+1); - math_emu_le(opcode, regs); + do_sig=math_emu_le(opcode, regs); break; case 0xb3: get_user(*((__u16 *) (opcode+2)), location+1); @@ -406,22 +315,15 @@ asmlinkage void data_exception(struct pt_regs * regs, long error_code) do_sig = 1; break; } - } else - do_sig = 1; - if (do_sig) { - current->thread.error_code = error_code; - current->thread.trap_no = 1; - force_sig(SIGILL, current); - die_if_no_fixup("illegal operation", regs, error_code); } +#endif + else + do_sig = 1; + if (do_sig) + do_trap(interruption_code, SIGILL, "data exception", regs, NULL); unlock_kernel(); } -#else -DO_ERROR(1, SIGILL, "illegal operation", illegal_op, current) -DO_ERROR(6, SIGILL, "specification exception", specification_exception, current) -DO_ERROR(7, SIGILL, "data exception", data_exception, current) -#endif /* CONFIG_IEEEFPU_EMULATION */ /* init is done in lowcore.S and head.S */ @@ -463,7 +365,7 @@ void handle_per_exception(struct pt_regs *regs) /* 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_crashed_task_info(); + show_regs(regs); /* Hopefully switching off per tracing will help us survive */ regs->psw.mask &= ~PSW_PER_MASK; } diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index aa8b0e5da..40ae70e8c 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile @@ -2,11 +2,17 @@ # Makefile for s390-specific library files.. # +ifdef SMP .S.o: - $(CC) $(AFLAGS) -traditional -c $< -o $*.o + $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o +else +.S.o: + $(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o +endif L_TARGET = lib.a -L_OBJS = checksum.o delay.o memset.o strcmp.o strncpy.o + +obj-y = checksum.o delay.o memset.o strcmp.o strncpy.o uaccess.o include $(TOPDIR)/Rules.make diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index ec3274487..012a95308 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -21,25 +21,30 @@ void __delay(unsigned long loops) { - __asm__ __volatile__( - "0: ahi %0,-1\n" - " jnm 0b" - : /* no outputs */ : "r" (loops) ); + /* + * To end the bloody studid and useless discussion about the + * BogoMips number I took the liberty to define the __delay + * function in a way that that resulting BogoMips number will + * yield the megahertz number of the cpu. The important function + * is udelay and that is done using the tod clock. -- martin. + */ + __asm__ __volatile__( + "0: brct %0,0b" + : /* no outputs */ : "r" (loops/2) ); } -inline void __const_udelay(unsigned long xloops) +/* + * Waits for 'usecs' microseconds using the tod clock + */ +void __udelay(unsigned long usecs) { + uint64_t start_cc, end_cc; - __asm__("LR 3,%1\n\t" - "MR 2,%2\n\t" - "LR %0,2\n\t" - : "=r" (xloops) - : "r" (xloops) , "r" (loops_per_sec) - : "2" , "3"); - __delay(xloops); + if (usecs == 0) + return; + asm volatile ("STCK %0" : "=m" (start_cc)); + do { + asm volatile ("STCK %0" : "=m" (end_cc)); + } while (((end_cc - start_cc)/4096) < usecs); } -void __udelay(unsigned long usecs) -{ - __const_udelay(usecs * 0x000010c6); /* 2**32 / 1000000 */ -} diff --git a/arch/s390/lib/strcmp.S b/arch/s390/lib/strcmp.S index d3f63942f..340edffb5 100644 --- a/arch/s390/lib/strcmp.S +++ b/arch/s390/lib/strcmp.S @@ -18,8 +18,8 @@ strcmp: CLST 2,3 JO .-4 JE strcmp_equal - IC 0,0(0,3) - IC 1,0(0,2) + IC 0,0(3) + IC 1,0(2) SR 1,0 strcmp_equal: LR 2,1 diff --git a/arch/s390/lib/strncpy.S b/arch/s390/lib/strncpy.S index 83578909c..3065be2b4 100644 --- a/arch/s390/lib/strncpy.S +++ b/arch/s390/lib/strncpy.S @@ -20,9 +20,9 @@ strncpy: SR 0,0 strncpy_loop: ICM 0,1,0(3) # ICM sets the cc, IC does not - LA 3,1(0,3) - STC 0,0(0,1) - LA 1,1(0,1) + LA 3,1(3) + STC 0,0(1) + LA 1,1(1) JZ strncpy_exit # ICM inserted a 0x00 BRCT 4,strncpy_loop # R4 -= 1, jump to strncpy_loop if > 0 strncpy_exit: diff --git a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S new file mode 100644 index 000000000..8044d156d --- /dev/null +++ b/arch/s390/lib/uaccess.S @@ -0,0 +1,51 @@ +/* + * arch/s390/lib/uaccess.S + * fixup routines for copy_{from|to}_user functions. + * + * s390 + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + * + * These functions have a non-standard call interface + */ + +#include <asm/lowcore.h> + + .text + .align 4 + .globl __copy_from_user_fixup +__copy_from_user_fixup: + l 1,__LC_PGM_OLD_PSW+4 + sll 4,1 + srl 4,1 +0: lhi 3,-4096 + sll 3,1 + srl 3,1 + n 3,__LC_TRANS_EXC_ADDR + sr 3,4 + bm 4(1) +1: mvcle 2,4,0 + b 4(1) + .section __ex_table,"a" + .long 1b,0b + .previous + + .align 4 + .text + .globl __copy_to_user_fixup +__copy_to_user_fixup: + l 1,__LC_PGM_OLD_PSW+4 + sll 4,1 + srl 4,1 +0: lhi 5,-4096 + sll 5,1 + srl 5,1 + n 5,__LC_TRANS_EXC_ADDR + sr 5,4 + bm 4(1) +1: mvcle 4,2,0 + b 4(1) + .section __ex_table,"a" + .long 1b,0b + .previous + diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile index cee7d4e6d..73e25bd30 100644 --- a/arch/s390/mm/Makefile +++ b/arch/s390/mm/Makefile @@ -8,6 +8,7 @@ # Note 2! The CFLAGS definition is now in the main makefile... O_TARGET := mm.o -O_OBJS := init.o fault.o ioremap.o extable.o + +obj-y := init.o fault.o ioremap.o extable.o include $(TOPDIR)/Rules.make diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index f20a9d49e..2c75918af 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -9,6 +9,7 @@ * Copyright (C) 1995 Linus Torvalds */ +#include <linux/config.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/kernel.h> @@ -26,6 +27,10 @@ #include <asm/pgtable.h> #include <asm/hardirq.h> +#ifdef CONFIG_SYSCTL +extern int sysctl_userprocess_debug; +#endif + extern void die(const char *,struct pt_regs *,long); /* @@ -48,6 +53,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) int write; unsigned long psw_mask; unsigned long psw_addr; + int si_code = SEGV_MAPERR; + int kernel_address = 0; /* * get psw mask of Program old psw to find out, @@ -65,58 +72,106 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) address = S390_lowcore.trans_exc_code&0x7ffff000; - if (in_irq()) - die("page fault from irq handler",regs,error_code); - tsk = current; mm = tsk->mm; + if (in_interrupt() || !mm) + goto no_context; + + + /* + * Check which address space the address belongs to + */ + switch (S390_lowcore.trans_exc_code & 3) + { + case 0: /* Primary Segment Table Descriptor */ + kernel_address = 1; + goto no_context; + + case 1: /* STD determined via access register */ + if (S390_lowcore.exc_access_id == 0) + { + kernel_address = 1; + goto no_context; + } + if (regs && S390_lowcore.exc_access_id < NUM_ACRS) + { + if (regs->acrs[S390_lowcore.exc_access_id] == 0) + { + kernel_address = 1; + goto no_context; + } + if (regs->acrs[S390_lowcore.exc_access_id] == 1) + { + /* user space address */ + break; + } + } + die("page fault via unknown access register", regs, error_code); + break; + + case 2: /* Secondary Segment Table Descriptor */ + case 3: /* Home Segment Table Descriptor */ + /* user space address */ + break; + } + + + /* + * When we get here, the fault happened in the current + * task's user address space, so we search the VMAs + */ + down(&mm->mmap_sem); vma = find_vma(mm, address); - if (!vma) { - printk("no vma for address %lX\n",address); + if (!vma) goto bad_area; - } if (vma->vm_start <= address) goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) { - printk("VM_GROWSDOWN not set, but address %lX \n",address); - printk("not in vma %p (start %lX end %lX)\n",vma, - vma->vm_start,vma->vm_end); + if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - } - if (expand_stack(vma, address)) { - printk("expand of vma failed address %lX\n",address); - printk("vma %p (start %lX end %lX)\n",vma, - vma->vm_start,vma->vm_end); + if (expand_stack(vma, address)) goto bad_area; - } /* * Ok, we have a good vm_area for this memory access, so * we can handle it.. */ good_area: write = 0; + si_code = SEGV_ACCERR; + switch (error_code & 0xFF) { case 0x04: /* write, present*/ write = 1; break; case 0x10: /* not present*/ case 0x11: /* not present*/ - if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) { - printk("flags %X of vma for address %lX wrong \n", - vma->vm_flags,address); - printk("vma %p (start %lX end %lX)\n",vma, - vma->vm_start,vma->vm_end); + if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) goto bad_area; - } break; default: printk("code should be 4, 10 or 11 (%lX) \n",error_code&0xFF); goto bad_area; } - handle_mm_fault(tsk, vma, address, write); + + /* + * If for any reason at all we couldn't handle the fault, + * make sure we exit gracefully rather than endlessly redo + * the fault. + */ + switch (handle_mm_fault(mm, vma, address, write)) { + case 1: + tsk->min_flt++; + break; + case 2: + tsk->maj_flt++; + break; + case 0: + goto do_sigbus; + default: + goto out_of_memory; + } up(&mm->mmap_sem); return; @@ -130,19 +185,32 @@ bad_area: /* User mode accesses just cause a SIGSEGV */ if (psw_mask & PSW_PROBLEM_STATE) { + struct siginfo si; tsk->thread.prot_addr = address; - tsk->thread.error_code = error_code; - tsk->thread.trap_no = 14; - + tsk->thread.trap_no = error_code; +#ifndef CONFIG_SYSCTL +#ifdef CONFIG_PROCESS_DEBUG printk("User process fault: interruption code 0x%lX\n",error_code); printk("failing address: %lX\n",address); - show_crashed_task_info(); - force_sig(SIGSEGV, tsk); + show_regs(regs); +#endif +#else + if (sysctl_userprocess_debug) { + printk("User process fault: interruption code 0x%lX\n", + error_code); + printk("failing address: %lX\n", address); + show_regs(regs); + } +#endif + si.si_signo = SIGSEGV; + si.si_code = si_code; + si.si_addr = (void*) address; + force_sig_info(SIGSEGV, &si, tsk); return; } +no_context: /* Are we prepared to handle this kernel fault? */ - if ((fixup = search_exception_table(regs->psw.addr)) != 0) { regs->psw.addr = fixup; return; @@ -151,53 +219,47 @@ bad_area: /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. - * - * First we check if it was the bootup rw-test, though.. */ - if (address < PAGE_SIZE) - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); + + if (kernel_address) + printk(KERN_ALERT "Unable to handle kernel pointer dereference" + " at virtual kernel address %08lx\n", address); else - printk(KERN_ALERT "Unable to handle kernel paging request"); - printk(" at virtual address %08lx\n",address); + printk(KERN_ALERT "Unable to handle kernel paging request" + " at virtual user address %08lx\n", address); /* * need to define, which information is useful here */ - lock_kernel(); die("Oops", regs, error_code); do_exit(SIGKILL); - unlock_kernel(); -} -/* - { - char c; - int i,j; - char *addr; - addr = ((char*) psw_addr)-0x20; - for (i=0;i<16;i++) { - if (i == 2) - printk("\n"); - printk ("%08X: ",(unsigned long) addr); - for (j=0;j<4;j++) { - printk("%08X ",*(unsigned long*)addr); - addr += 4; - } - addr -=0x10; - printk(" | "); - for (j=0;j<16;j++) { - printk("%c",(c=*addr++) < 0x20 ? '.' : c ); - } - - printk("\n"); - } - printk("\n"); - } +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. */ +out_of_memory: + up(&mm->mmap_sem); + printk("VM: killing process %s\n", tsk->comm); + if (psw_mask & PSW_PROBLEM_STATE) + do_exit(SIGKILL); + goto no_context; +do_sigbus: + up(&mm->mmap_sem); + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + tsk->thread.prot_addr = address; + tsk->thread.trap_no = error_code; + force_sig(SIGBUS, tsk); - + /* Kernel mode? Handle exceptions or die */ + if (!(psw_mask & PSW_PROBLEM_STATE)) + goto no_context; +} diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 177e5e8f2..e1acfa063 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -52,10 +52,10 @@ static unsigned long totalram_pages; * data and COW. */ -pgd_t swapper_pg_dir[512] __attribute__ ((__aligned__ (4096))); -unsigned long empty_bad_page[1024] __attribute__ ((__aligned__ (4096))); -unsigned long empty_zero_page[1024] __attribute__ ((__aligned__ (4096))); -pte_t empty_bad_pte_table[1024] __attribute__ ((__aligned__ (4096))); +pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); +char empty_bad_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); +char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); +pte_t empty_bad_pte_table[PTRS_PER_PTE] __attribute__((__aligned__(PAGE_SIZE))); static int test_access(unsigned long loc) { @@ -104,47 +104,6 @@ static inline void invalidate_page(pte_t *pte) pte_clear(pte++); } -void __handle_bad_pmd(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - pmd_val(*pmd) = _PAGE_TABLE + __pa(get_bad_pte_table()); -} - -void __handle_bad_pmd_kernel(pmd_t *pmd) -{ - pmd_ERROR(*pmd); - pmd_val(*pmd) = _KERNPG_TABLE + __pa(get_bad_pte_table()); -} - -pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long offset) -{ - pte_t *pte; - - pte = (pte_t *) __get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (pte) { - invalidate_page(pte); - pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(pte); - pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(pte)+1024; - pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(pte)+2048; - pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(pte)+3072; - return pte + offset; - } - pte = get_bad_pte_table(); - pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(pte); - pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(pte)+1024; - pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(pte)+2048; - pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(pte)+3072; - return NULL; - } - free_page((unsigned long)pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + offset; -} - pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) { unsigned long pte; @@ -167,10 +126,8 @@ pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset) return NULL; } free_page(pte); - if (pmd_bad(*pmd)) { - __handle_bad_pmd(pmd); - return NULL; - } + if (pmd_bad(*pmd)) + BUG(); return (pte_t *) pmd_page(*pmd) + offset; } @@ -180,7 +137,7 @@ int do_check_pgt_cache(int low, int high) if(pgtable_cache_size > high) { do { if(pgd_quicklist) - free_pgd_slow(get_pgd_fast()), freed++; + free_pgd_slow(get_pgd_fast()), freed += 2; if(pmd_quicklist) free_pmd_slow(get_pmd_fast()), freed++; if(pte_quicklist) @@ -245,6 +202,7 @@ void __init paging_init(void) unsigned long address=0; unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE; unsigned long end_mem = (unsigned long) __va(max_low_pfn*PAGE_SIZE); + static const int ssm_mask = 0x04000000L; /* unmap whole virtual address space */ @@ -283,8 +241,9 @@ void __init paging_init(void) /* enable virtual mapping in kernel mode */ __asm__ __volatile__(" LCTL 1,1,%0\n" " LCTL 7,7,%0\n" - " LCTL 13,13,%0" - : :"m" (pgdir_k)); + " LCTL 13,13,%0\n" + " SSM %1" + : : "m" (pgdir_k), "m" (ssm_mask)); local_flush_tlb(); @@ -378,6 +337,7 @@ void si_meminfo(struct sysinfo *val) val->sharedram = 0; val->freeram = nr_free_pages(); val->bufferram = atomic_read(&buffermem_pages); + val->totalhigh = 0; + val->freehigh = 0; val->mem_unit = PAGE_SIZE; - return; } diff --git a/arch/s390/mm/ioremap.c b/arch/s390/mm/ioremap.c index f9f0024c4..38acc4a22 100644 --- a/arch/s390/mm/ioremap.c +++ b/arch/s390/mm/ioremap.c @@ -33,8 +33,8 @@ static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned l printk("remap_area_pte: page already exists\n"); BUG(); } - set_pte(pte, mk_pte_phys(phys_addr, __pgprot(_PAGE_PRESENT | - _PAGE_DIRTY | _PAGE_ACCESSED | flags))); + set_pte(pte, mk_pte_phys(phys_addr, + __pgprot(_PAGE_PRESENT | flags))); address += PAGE_SIZE; phys_addr += PAGE_SIZE; pte++; diff --git a/arch/s390/tools/dasdfmt/Makefile b/arch/s390/tools/dasdfmt/Makefile index f63ff468b..b60641bbc 100644 --- a/arch/s390/tools/dasdfmt/Makefile +++ b/arch/s390/tools/dasdfmt/Makefile @@ -1,7 +1,7 @@ all: dasdfmt dasdfmt: dasdfmt.c - $(CROSS_COMPILE)gcc -o $@ $^ + $(CC) -o $@ $^ $(STRIP) $@ clean: diff --git a/arch/s390/tools/dasdfmt/dasdfmt.8 b/arch/s390/tools/dasdfmt/dasdfmt.8 index b08244322..9e6a4e89e 100644 --- a/arch/s390/tools/dasdfmt/dasdfmt.8 +++ b/arch/s390/tools/dasdfmt/dasdfmt.8 @@ -3,8 +3,7 @@ .SH NAME dasdfmt \- formatting of DSAD (ECKD) disk drives. .SH SYNOPSIS -\fBdasdfmt\fR [-tvyV] [-b \fIblockSize\fR] [\fIblockRange\fI] - \fIdiskSpec\fR +\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR .SH DESCRIPTION \fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of @@ -25,6 +24,10 @@ Increases verbosity. Start formatting without further user-confirmation. .TP +\fB-L\fR +Omit the writing of a disk label after formatting. + +.TP \fB-V\fR Print version number and exit. @@ -35,26 +38,17 @@ and always be a power of two. Due due some limitations in the driver, it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR. .TP -\fIblockRange\fR -This parameter specifies the number of the first and last block to be -formatted. If this parameter is \fBomitted\fR, formatting the \fBwhole\fR disk -is assumed. The \fIblockRange\fR can be specified in two different formats: -.sp - \fB-s\fR \fIstartBlock\fR \fB-e\fR \fIendBlock\fR -.br -or -.br - \fB-r\fR \fIstartBlock\fR-\fIendBlock\fR -.sp -If \fIstartBlock\fR is omitted, block \fB0\fR is assumed. If -\fIendBlock\fR is omitted, the last block of the disk is assumed. +\fB-l\fR \fIdiskLabel\fR +Specify the label to be written to disk after formatting. If no label is +specified, a sensible default is used. \fIdiskLabel\fR is interpreted as +ASCII string and is automatically converted to EBCDIC. .TP \fIdiskSpec\fR This parameter specified the device to be formatted. It also can be given in two variants: .sp - \fB-f\fR \fB/dev/dd\fR\fIX\fR + \fB-f\fR \fB/dev/dasd\fR\fIX\fR .br or .br @@ -63,7 +57,7 @@ or The first form uses the commonly used .SM UNIX device notation where \fIX\fR is a single lowercase letter. -The second form uses simply the VM vdev number. +The second form uses simply the device number. .SH BUGS None so far ;-) diff --git a/arch/s390/tools/dasdfmt/dasdfmt.c b/arch/s390/tools/dasdfmt/dasdfmt.c index 1726e7061..2820fc91d 100644 --- a/arch/s390/tools/dasdfmt/dasdfmt.c +++ b/arch/s390/tools/dasdfmt/dasdfmt.c @@ -12,6 +12,8 @@ * detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them */ +/* #define _LINUX_BLKDEV_H */ + #include <unistd.h> #include <stdio.h> #include <sys/types.h> @@ -25,19 +27,25 @@ #include <string.h> #include <dirent.h> #include <mntent.h> -#include "../../../drivers/s390/block/dasd.h" /* uses DASD_PARTN_BITS */ #define __KERNEL__ /* we want to use kdev_t and not have to define it */ #include <linux/kdev_t.h> #undef __KERNEL__ +#include <linux/fs.h> +#include <asm/dasd.h> +#include <linux/hdreg.h> + #define EXIT_MISUSE 1 #define EXIT_BUSY 2 #define TEMPFILENAME "/tmp/ddfXXXXXX" #define TEMPFILENAMECHARS 8 /* 8 characters are fixed in all temp filenames */ -#define IOCTL_COMMAND 'D' << 8 #define SLASHDEV "/dev/" #define PROC_DASD_DEVICES "/proc/dasd/devices" +/* _PATH_MOUNTED is /etc/mtab - /proc/mounts does not show root-fs correctly */ +#define PROC_MOUNTS _PATH_MOUNTED +#define PROC_SWAPS "/proc/swaps" #define DASD_DRIVER_NAME "dasd" +#define LABEL_LENGTH 10 #define PROC_LINE_LENGTH 80 #define ERR_LENGTH 80 @@ -66,24 +74,108 @@ ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \ "is in invalid format\n",prog_name);} -typedef struct { - int start_unit; - int stop_unit; - int blksize; -} format_data_t; - -char prog_name[]="dasd_format"; +char *prog_name;/*="dasdfmt";*/ char tempfilename[]=TEMPFILENAME; +__u8 _ascebc[256] = +{ + /*00 NUL SOH STX ETX EOT ENQ ACK BEL */ + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, + /*08 BS HT LF VT FF CR SO SI */ + /* ->NL */ + 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, + /*18 CAN EM SUB ESC FS GS RS US */ + /* ->IGS ->IRS ->IUS */ + 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F, + /*20 SP ! " # $ % & ' */ + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, + /*28 ( ) * + , - . / */ + 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, + /*30 0 1 2 3 4 5 6 7 */ + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + /*38 8 9 : ; < = > ? */ + 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F, + /*40 @ A B C D E F G */ + 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + /*48 H I J K L M N O */ + 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, + /*50 P Q R S T U V W */ + 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, + /*58 X Y Z [ \ ] ^ _ */ + 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D, + /*60 ` a b c d e f g */ + 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + /*68 h i j k l m n o */ + 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, + /*70 p q r s t u v w */ + 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, + /*78 x y z { | } ~ DL */ + 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07, + /*80*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*88*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*90*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*98*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*A0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*A8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*B0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*B8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*C0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*C8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*D0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*D8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*E0 sz */ + 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*E8*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*F0*/ + 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, + /*F8*/ + 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF +}; + +void convert_label(char *str) +{ + int i; + for (i=0;i<LABEL_LENGTH;i++) str[i]=_ascebc[str[i]]; +} + void exit_usage(int exitcode) { - printf("Usage: %s [-htvyV] [-b blocksize] <range> <diskspec>\n\n", - prog_name); - printf(" where <range> is either\n"); - printf(" -s start_track -e end_track\n"); +#ifdef RANGE_FORMATTING + printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] [<range>] " \ + "<diskspec>\n\n",prog_name); +#else /* RANGE_FORMATTING */ + printf("Usage: %s [-htvyLV] [-l <label>] [-b <blocksize>] " \ + "<diskspec>\n\n",prog_name); +#endif /* RANGE_FORMATTING */ + printf(" -t means testmode\n"); + printf(" -v means verbose mode\n"); + printf(" -V means print version\n"); + printf(" -L means don't write disk label\n"); + printf(" <label> is a label which is converted to EBCDIC and " \ + "written to disk\n"); + printf(" <blocksize> has to be power of 2 and at least 512\n"); +#ifdef RANGE_FORMATTING + printf(" <range> is either\n"); + printf(" -s <start_track> -e <end_track>\n"); printf(" or\n"); - printf(" -r start_track-end_track\n"); + printf(" -r <start_track>-<end_track>\n"); +#endif /* RANGE_FORMATTING */ printf(" and <diskspec> is either\n"); printf(" -f /dev/dasdX\n"); printf(" or\n"); @@ -106,9 +198,9 @@ get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode) PROC_DASD_DEVICES ": %s (do you have the /proc " \ "filesystem enabled?)\n",prog_name,strerror(errno)); - fgets(line,sizeof(line),file); /* omit first line */ + /* fgets(line,sizeof(line),file); omit first line */ while (fgets(line,sizeof(line),file)!=NULL) { - rc=sscanf(line,"%X%d%d",&d,&ma_i,&mi_i); + rc=sscanf(line,"%X %*[(A-Z)] at (%d:%d)",&d,&ma_i,&mi_i); ma=ma_i; mi=mi_i; if ( (rc==3) && @@ -253,6 +345,7 @@ ask_user_for_data(format_data_t params) char *str; char output[60],o2[12]; +#ifdef RANGE_FORMATTING i=params.start_unit; do { params.start_unit=i; @@ -284,6 +377,7 @@ ask_user_for_data(format_data_t params) ASK_CHECK_PARAM(CHECK_END); } } while (rc!=1); +#endif /* RANGE_FORMATTING */ i=params.blksize; do { @@ -320,8 +414,8 @@ check_mounted(int major, int minor) /* * first, check filesystems */ - if (!(f = fopen(_PATH_MOUNTED, "r"))) - ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", _PATH_MOUNTED, + if (!(f = fopen(PROC_MOUNTS, "r"))) + ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", PROC_MOUNTS, strerror(errno)); while ((ment = getmntent(f))) { if (stat(ment->mnt_fsname, &stbuf) == 0) @@ -337,8 +431,8 @@ check_mounted(int major, int minor) /* * second, check active swap spaces */ - if (!(f = fopen("/proc/swaps", "r"))) - ERRMSG_EXIT(EXIT_FAILURE, "/proc/swaps: %s", strerror(errno)); + if (!(f = fopen(PROC_SWAPS, "r"))) + ERRMSG_EXIT(EXIT_FAILURE, PROC_SWAPS " %s", strerror(errno)); /* * skip header line */ @@ -362,12 +456,15 @@ check_mounted(int major, int minor) void do_format_dasd(char *dev_name,format_data_t format_params,int testmode, - int verbosity,int withoutprompt) + int verbosity,int writenolabel,int labelspec, + char *label,int withoutprompt,int devno) { int fd,rc; struct stat stat_buf; kdev_t minor_no,major_no; - int devno; + int new_blksize; + unsigned int label_position; + struct hd_geometry new_geometry; char inp_buffer[5]; /* to contain yes */ fd=open(dev_name,O_RDWR); @@ -390,6 +487,10 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode, minor_no=MINOR(stat_buf.st_rdev); } check_mounted(major_no, minor_no); + + if ((!writenolabel) && (!labelspec)) { + sprintf(label,"LNX1 x%04x",devno); + } if ( ((withoutprompt)&&(verbosity>=1)) || (!withoutprompt) ) { @@ -400,6 +501,11 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode, printf(" Device number of device : 0x%x\n",devno); printf(" Major number of device : %u\n",major_no); printf(" Minor number of device : %u\n",minor_no); + printf(" Labelling device : %s\n",(writenolabel)? + "no":"yes"); + if (!writenolabel) + printf(" Disk label : %s\n",label); +#ifdef RANGE_FORMATTING printf(" Start track : %d\n" \ ,format_params.start_unit); printf(" End track : "); @@ -407,6 +513,7 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode, printf("last track of disk\n"); else printf("%d\n",format_params.stop_unit); +#endif /* RANGE_FORMATTING */ printf(" Blocksize : %d\n" \ ,format_params.blksize); if (testmode) printf("Test mode active, omitting ioctl.\n"); @@ -416,8 +523,8 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode, if (!withoutprompt) { printf("\n--->> ATTENTION! <<---\n"); printf("All data in the specified range of that " \ - "device will be lost.\nType yes to continue" \ - ", no will leave the disk untouched: "); + "device will be lost.\nType \"yes\" to " \ + "continue, no will leave the disk untouched: "); fgets(inp_buffer,sizeof(inp_buffer),stdin); if (strcasecmp(inp_buffer,"yes") && strcasecmp(inp_buffer,"yes\n")) { @@ -430,13 +537,70 @@ do_format_dasd(char *dev_name,format_data_t format_params,int testmode, if ( !( (withoutprompt)&&(verbosity<1) )) printf("Formatting the device. This may take a " \ "while (get yourself a coffee).\n"); - rc=ioctl(fd,IOCTL_COMMAND,format_params); + rc=ioctl(fd,BIODASDFORMAT,format_params); if (rc) ERRMSG_EXIT(EXIT_FAILURE,"%s: the dasd driver " \ "returned with the following error " \ "message:\n%s\n",prog_name,strerror(errno)); printf("Finished formatting the device.\n"); + if (!writenolabel) { + if (verbosity>0) + printf("Retrieving disk geometry... "); + + rc=ioctl(fd,HDIO_GETGEO,&new_geometry); + if (rc) { + ERRMSG("%s: the ioctl call to get geometry " \ + "returned with the following error " \ + "message:\n%s\n",prog_name, + strerror(errno)); + goto reread; + } + + + rc=ioctl(fd,BLKGETSIZE,&new_blksize); + if (rc) { + ERRMSG("%s: the ioctl call to get blocksize " \ + "returned with the following error " \ + "message:\n%s\n",prog_name, + strerror(errno)); + goto reread; + } + + if (verbosity>0) printf("done\n"); + + label_position=new_geometry.start*new_blksize; + + if (verbosity>0) printf("Writing label... "); + convert_label(label); + rc=lseek(fd,label_position,SEEK_SET); + if (rc!=label_position) { + ERRMSG("%s: lseek on the device to %i " \ + "failed with the following error " \ + "message:\n%s\n",prog_name, + label_position,strerror(errno)); + goto reread; + } + rc=write(fd,label,LABEL_LENGTH); + if (rc!=LABEL_LENGTH) { + ERRMSG("%s: writing the label only wrote %d " \ + "bytes.\n",prog_name,rc); + goto reread; + } + + sync(); + sync(); + + if (verbosity>0) printf("done\n"); + } + reread: + printf("Rereading the partition table... "); + rc=ioctl(fd,BLKRRPART,NULL); + if (rc) { + ERRMSG("%s: error during rereading the partition " \ + "table: %s.\n",prog_name,strerror(errno)); + } else printf("done.\n"); + break; } @@ -452,11 +616,13 @@ int main(int argc,char *argv[]) { int verbosity; int testmode; int withoutprompt; + int writenolabel,labelspec; char *dev_name; int devno; char *dev_filename,*devno_param_str,*range_param_str; char *start_param_str,*end_param_str,*blksize_param_str; + char label[LABEL_LENGTH+1]; format_data_t format_params; @@ -465,23 +631,30 @@ int main(int argc,char *argv[]) { char *endptr; char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */ - int i1,i2; + int i,i1,i2; char *str; int start_specified,end_specified,blksize_specified; int devfile_specified,devno_specified,range_specified; /******************* initialization ********************/ + prog_name=argv[0]; endptr=NULL; /* set default values */ - format_params.start_unit=0; - format_params.stop_unit=-1; - format_params.blksize=4096; + format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT; + format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT; + format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE; + format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY; testmode=0; verbosity=0; withoutprompt=0; + writenolabel=0; + labelspec=0; + for (i=0;i<LABEL_LENGTH;i++) label[i]=' '; + label[LABEL_LENGTH]=0; + start_specified=end_specified=blksize_specified=0; devfile_specified=devno_specified=range_specified=0; @@ -490,7 +663,10 @@ int main(int argc,char *argv[]) { /* avoid error message generated by getopt */ opterr=0; - while ( (oc=getopt(argc,argv,"r:s:e:b:n:f:hty?vV")) !=EOF) { +#ifdef RANGE_FORMATTING + while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:hLty?vV")) !=EOF) { +#endif /* RANGE_FORMATTING */ + while ( (oc=getopt(argc,argv,"b:n:l:f:hLty?vV")) !=EOF) { switch (oc) { case 'y': withoutprompt=1; @@ -515,6 +691,18 @@ int main(int argc,char *argv[]) { printf("%s version 0.99\n",prog_name); exit(0); + case 'l': + strncpy(label,optarg,LABEL_LENGTH); + if (strlen(optarg)<LABEL_LENGTH) + label[strlen(optarg)]=' '; + labelspec++; + break; + + case 'L': + writenolabel++; + break; + +#ifdef RANGE_FORMATTING case 's' : start_param_str=optarg; start_specified++; @@ -525,6 +713,12 @@ int main(int argc,char *argv[]) { end_specified++; break; + case 'r' : + range_param_str=optarg; + range_specified++; + break; +#endif /* RANGE_FORMATTING */ + case 'b' : blksize_param_str=optarg; blksize_specified++; @@ -539,10 +733,6 @@ int main(int argc,char *argv[]) { dev_filename=optarg; devfile_specified++; break; - case 'r' : - range_param_str=optarg; - range_specified++; - break; } } @@ -594,6 +784,8 @@ int main(int argc,char *argv[]) { CHECK_SPEC_MAX_ONCE(start_specified,"start track"); CHECK_SPEC_MAX_ONCE(end_specified,"end track"); CHECK_SPEC_MAX_ONCE(blksize_specified,"blocksize"); + CHECK_SPEC_MAX_ONCE(labelspec,"label"); + CHECK_SPEC_MAX_ONCE(writenolabel,"omit-label-writing flag"); if (devno_specified) PARSE_PARAM_INTO(devno,devno_param_str,16,"device number"); @@ -616,9 +808,9 @@ int main(int argc,char *argv[]) { str=check_param(CHECK_ALL,format_params); if (str!=NULL) ERRMSG_EXIT(EXIT_MISUSE,"%s: %s\n",prog_name,str); - /*************** issue the real command *****************/ + /******* issue the real command and reread part table *******/ do_format_dasd(dev_name,format_params,testmode,verbosity, - withoutprompt); + writenolabel,labelspec,label,withoutprompt,devno); /*************** cleanup ********************************/ if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) { diff --git a/arch/s390/tools/silo/Makefile b/arch/s390/tools/silo/Makefile index fb100e1b9..62b11d7da 100644 --- a/arch/s390/tools/silo/Makefile +++ b/arch/s390/tools/silo/Makefile @@ -1,13 +1,13 @@ all: silo silo.o: silo.c - $(CROSS_COMPILE)gcc -c -o silo.o -O2 silo.c + $(CC) -c -o silo.o -O2 silo.c cfg.o: cfg.c - $(CROSS_COMPILE)gcc -c -o cfg.o -O2 cfg.c + $(CC) -c -o cfg.o -O2 cfg.c silo: silo.o cfg.o - $(CROSS_COMPILE)gcc -o $@ $^ + $(CC) -o $@ $^ $(STRIP) $@ clean: diff --git a/arch/s390/tools/silo/silo.c b/arch/s390/tools/silo/silo.c index 827082f5c..9ac04ac2b 100644 --- a/arch/s390/tools/silo/silo.c +++ b/arch/s390/tools/silo/silo.c @@ -45,7 +45,7 @@ CONFIG cf_options[] = { /* from dasd.h */ #define DASD_PARTN_BITS 2 -#define BIODASDRWTB _IOWR('D',5,int) +#define BIODASDRWTB _IOWR('D',0,int) /* end */ #define SILO_CFG "/etc/silo.conf" @@ -554,7 +554,7 @@ int main (int argct, char *argv[]) { int rc = 0; - char *save; + char *save=NULL; char *tmpdir=getenv("TMPDIR"); if (tmpdir) { NTRY( save=(char*)malloc(strlen(tmpdir))); diff --git a/arch/s390/vmlinux.lds b/arch/s390/vmlinux.lds index b1b556d14..4d93bcc7a 100644 --- a/arch/s390/vmlinux.lds +++ b/arch/s390/vmlinux.lds @@ -26,6 +26,10 @@ SECTIONS __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } + __stop___kallsyms = .; + _etext = .; /* End of text section */ .data : { /* Data */ |