diff options
author | David Woodhouse <dwmw2@infradead.org> | 2006-10-01 18:55:53 +0200 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2006-10-01 18:55:53 +0200 |
commit | 8a84fc15ae5cafcc366dd85cf8e1ab2040679abc (patch) | |
tree | 5d8dce194c9667fa92e9ec9f545cec867a9a1e0d /arch/s390 | |
parent | [MTD ONENAND] Check OneNAND lock scheme & all block unlock command support (diff) | |
parent | Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/agpgart (diff) | |
download | linux-8a84fc15ae5cafcc366dd85cf8e1ab2040679abc.tar.xz linux-8a84fc15ae5cafcc366dd85cf8e1ab2040679abc.zip |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Manually resolve conflict in include/mtd/Kbuild
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'arch/s390')
57 files changed, 5073 insertions, 3192 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 2f4f70c4dbb2..f900a516f099 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -51,6 +51,10 @@ config 64BIT Select this option if you have a 64 bit IBM zSeries machine and want to use the 64 bit addressing mode. +config 32BIT + bool + default y if !64BIT + config SMP bool "Symmetric multi-processing support" ---help--- @@ -149,6 +153,14 @@ config MARCH_Z990 This will be slightly faster but does not work on older machines such as the z900. +config MARCH_Z9_109 + bool "IBM System z9" + help + Select this to enable optimizations for IBM System z9-109, IBM + System z9 Enterprise Class (z9 EC), and IBM System z9 Business + Class (z9 BC). The kernel will be slightly faster but will not + work on older machines such as the z990, z890, z900, and z800. + endchoice config PACK_STACK @@ -460,8 +472,7 @@ config S390_HYPFS_FS information in an s390 hypervisor environment. config KEXEC - bool "kexec system call (EXPERIMENTAL)" - depends on EXPERIMENTAL + bool "kexec system call" help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot @@ -487,8 +498,22 @@ source "drivers/net/Kconfig" source "fs/Kconfig" +menu "Instrumentation Support" + source "arch/s390/oprofile/Kconfig" +config KPROBES + bool "Kprobes (EXPERIMENTAL)" + depends on EXPERIMENTAL && MODULES + help + Kprobes allows you to trap at almost any kernel address and + execute a callback function. register_kprobe() establishes + a probepoint and specifies the callback. Kprobes is useful + for kernel debugging, non-intrusive instrumentation and testing. + If in doubt, say "N". + +endmenu + source "arch/s390/Kconfig.debug" source "security/Kconfig" diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 74ef57dcfa60..5deb9f7544a1 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -33,6 +33,7 @@ endif cflags-$(CONFIG_MARCH_G5) += $(call cc-option,-march=g5) cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900) cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990) +cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109) # # Prevent tail-call optimizations, to get clearer backtraces: diff --git a/arch/s390/appldata/appldata.h b/arch/s390/appldata/appldata.h index 71d65eb30650..0429481dea63 100644 --- a/arch/s390/appldata/appldata.h +++ b/arch/s390/appldata/appldata.h @@ -29,22 +29,6 @@ #define CTL_APPLDATA_NET_SUM 2125 #define CTL_APPLDATA_PROC 2126 -#ifndef CONFIG_64BIT - -#define APPLDATA_START_INTERVAL_REC 0x00 /* Function codes for */ -#define APPLDATA_STOP_REC 0x01 /* DIAG 0xDC */ -#define APPLDATA_GEN_EVENT_RECORD 0x02 -#define APPLDATA_START_CONFIG_REC 0x03 - -#else - -#define APPLDATA_START_INTERVAL_REC 0x80 -#define APPLDATA_STOP_REC 0x81 -#define APPLDATA_GEN_EVENT_RECORD 0x82 -#define APPLDATA_START_CONFIG_REC 0x83 - -#endif /* CONFIG_64BIT */ - #define P_INFO(x...) printk(KERN_INFO MY_PRINT_NAME " info: " x) #define P_ERROR(x...) printk(KERN_ERR MY_PRINT_NAME " error: " x) #define P_WARNING(x...) printk(KERN_WARNING MY_PRINT_NAME " status: " x) diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index a0a94e0ef8d1..2b1e6c9a6e0e 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -14,20 +14,20 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/errno.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/smp.h> #include <linux/interrupt.h> #include <linux/proc_fs.h> -#include <linux/page-flags.h> +#include <linux/mm.h> #include <linux/swap.h> #include <linux/pagemap.h> #include <linux/sysctl.h> -#include <asm/timer.h> -//#include <linux/kernel_stat.h> #include <linux/notifier.h> #include <linux/cpu.h> #include <linux/workqueue.h> +#include <asm/appldata.h> +#include <asm/timer.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/smp.h> #include "appldata.h" @@ -39,34 +39,6 @@ #define TOD_MICRO 0x01000 /* nr. of TOD clock units for 1 microsecond */ - -/* - * Parameter list for DIAGNOSE X'DC' - */ -#ifndef CONFIG_64BIT -struct appldata_parameter_list { - u16 diag; /* The DIAGNOSE code X'00DC' */ - u8 function; /* The function code for the DIAGNOSE */ - u8 parlist_length; /* Length of the parameter list */ - u32 product_id_addr; /* Address of the 16-byte product ID */ - u16 reserved; - u16 buffer_length; /* Length of the application data buffer */ - u32 buffer_addr; /* Address of the application data buffer */ -}; -#else -struct appldata_parameter_list { - u16 diag; - u8 function; - u8 parlist_length; - u32 unused01; - u16 reserved; - u16 buffer_length; - u32 unused02; - u64 product_id_addr; - u64 buffer_addr; -}; -#endif /* CONFIG_64BIT */ - /* * /proc entries (sysctl) */ @@ -181,46 +153,17 @@ static void appldata_work_fn(void *data) int appldata_diag(char record_nr, u16 function, unsigned long buffer, u16 length, char *mod_lvl) { - unsigned long ry; - struct appldata_product_id { - char prod_nr[7]; /* product nr. */ - char prod_fn[2]; /* product function */ - char record_nr; /* record nr. */ - char version_nr[2]; /* version */ - char release_nr[2]; /* release */ - char mod_lvl[2]; /* modification lvl. */ - } appldata_product_id = { - /* all strings are EBCDIC, record_nr is byte */ + struct appldata_product_id id = { .prod_nr = {0xD3, 0xC9, 0xD5, 0xE4, - 0xE7, 0xD2, 0xD9}, /* "LINUXKR" */ - .prod_fn = {0xD5, 0xD3}, /* "NL" */ - .record_nr = record_nr, - .version_nr = {0xF2, 0xF6}, /* "26" */ - .release_nr = {0xF0, 0xF1}, /* "01" */ - .mod_lvl = {mod_lvl[0], mod_lvl[1]}, - }; - struct appldata_parameter_list appldata_parameter_list = { - .diag = 0xDC, - .function = function, - .parlist_length = - sizeof(appldata_parameter_list), - .buffer_length = length, - .product_id_addr = - (unsigned long) &appldata_product_id, - .buffer_addr = virt_to_phys((void *) buffer) + 0xE7, 0xD2, 0xD9}, /* "LINUXKR" */ + .prod_fn = 0xD5D3, /* "NL" */ + .version_nr = 0xF2F6, /* "26" */ + .release_nr = 0xF0F1, /* "01" */ }; - if (!MACHINE_IS_VM) - return -ENOSYS; - ry = -1; - asm volatile( - "diag %1,%0,0xDC\n\t" - : "=d" (ry) - : "d" (&appldata_parameter_list), - "m" (appldata_parameter_list), - "m" (appldata_product_id) - : "cc"); - return (int) ry; + id.record_nr = record_nr; + id.mod_lvl = (mod_lvl[0]) << 8 | mod_lvl[1]; + return appldata_asm(&id, function, (void *) buffer, length); } /************************ timer, work, DIAG <END> ****************************/ diff --git a/arch/s390/appldata/appldata_mem.c b/arch/s390/appldata/appldata_mem.c index ab3b0765a64e..8aea3698a77b 100644 --- a/arch/s390/appldata/appldata_mem.c +++ b/arch/s390/appldata/appldata_mem.c @@ -117,8 +117,7 @@ static void appldata_get_mem_data(void *data) mem_data->pgpgout = ev[PGPGOUT] >> 1; mem_data->pswpin = ev[PSWPIN]; mem_data->pswpout = ev[PSWPOUT]; - mem_data->pgalloc = ev[PGALLOC_HIGH] + ev[PGALLOC_NORMAL] + - ev[PGALLOC_DMA]; + mem_data->pgalloc = ev[PGALLOC_NORMAL] + ev[PGALLOC_DMA]; mem_data->pgfault = ev[PGFAULT]; mem_data->pgmajfault = ev[PGMAJFAULT]; diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c index 161acc5c8a1b..76a15523ae9e 100644 --- a/arch/s390/appldata/appldata_os.c +++ b/arch/s390/appldata/appldata_os.c @@ -16,6 +16,7 @@ #include <linux/kernel_stat.h> #include <linux/netdevice.h> #include <linux/sched.h> +#include <asm/appldata.h> #include <asm/smp.h> #include "appldata.h" diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 5713c7e5bd16..15c9eec02928 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -16,9 +16,9 @@ * */ +#include <crypto/algapi.h> #include <linux/module.h> #include <linux/init.h> -#include <linux/crypto.h> #include "crypt_s390.h" #define AES_MIN_KEY_SIZE 16 @@ -34,13 +34,16 @@ int has_aes_256 = 0; struct s390_aes_ctx { u8 iv[AES_BLOCK_SIZE]; u8 key[AES_MAX_KEY_SIZE]; + long enc; + long dec; int key_len; }; static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, - unsigned int key_len, u32 *flags) + unsigned int key_len) { struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; switch (key_len) { case 16: @@ -110,133 +113,206 @@ static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) } } -static unsigned int aes_encrypt_ecb(const struct cipher_desc *desc, u8 *out, - const u8 *in, unsigned int nbytes) -{ - struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; - /* only use complete blocks */ - nbytes &= ~(AES_BLOCK_SIZE - 1); +static struct crypto_alg aes_alg = { + .cra_name = "aes", + .cra_driver_name = "aes-s390", + .cra_priority = CRYPT_S390_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s390_aes_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = AES_MIN_KEY_SIZE, + .cia_max_keysize = AES_MAX_KEY_SIZE, + .cia_setkey = aes_set_key, + .cia_encrypt = aes_encrypt, + .cia_decrypt = aes_decrypt, + } + } +}; + +static int ecb_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); - switch (sctx->key_len) { + switch (key_len) { case 16: - ret = crypt_s390_km(KM_AES_128_ENCRYPT, &sctx->key, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); + sctx->enc = KM_AES_128_ENCRYPT; + sctx->dec = KM_AES_128_DECRYPT; break; case 24: - ret = crypt_s390_km(KM_AES_192_ENCRYPT, &sctx->key, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); + sctx->enc = KM_AES_192_ENCRYPT; + sctx->dec = KM_AES_192_DECRYPT; break; case 32: - ret = crypt_s390_km(KM_AES_256_ENCRYPT, &sctx->key, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); + sctx->enc = KM_AES_256_ENCRYPT; + sctx->dec = KM_AES_256_DECRYPT; break; } - return nbytes; + + return aes_set_key(tfm, in_key, key_len); } -static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out, - const u8 *in, unsigned int nbytes) +static int ecb_aes_crypt(struct blkcipher_desc *desc, long func, void *param, + struct blkcipher_walk *walk) { - struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; + int ret = blkcipher_walk_virt(desc, walk); + unsigned int nbytes; - /* only use complete blocks */ - nbytes &= ~(AES_BLOCK_SIZE - 1); + while ((nbytes = walk->nbytes)) { + /* only use complete blocks */ + unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1); + u8 *out = walk->dst.virt.addr; + u8 *in = walk->src.virt.addr; - switch (sctx->key_len) { - case 16: - ret = crypt_s390_km(KM_AES_128_DECRYPT, &sctx->key, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); - break; - case 24: - ret = crypt_s390_km(KM_AES_192_DECRYPT, &sctx->key, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); - break; - case 32: - ret = crypt_s390_km(KM_AES_256_DECRYPT, &sctx->key, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); - break; + ret = crypt_s390_km(func, param, out, in, n); + BUG_ON((ret < 0) || (ret != n)); + + nbytes &= AES_BLOCK_SIZE - 1; + ret = blkcipher_walk_done(desc, walk, nbytes); } - return nbytes; + + return ret; } -static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out, - const u8 *in, unsigned int nbytes) +static int ecb_aes_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) { - struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; + struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - /* only use complete blocks */ - nbytes &= ~(AES_BLOCK_SIZE - 1); + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_aes_crypt(desc, sctx->enc, sctx->key, &walk); +} - memcpy(&sctx->iv, desc->info, AES_BLOCK_SIZE); - switch (sctx->key_len) { +static int ecb_aes_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_aes_crypt(desc, sctx->dec, sctx->key, &walk); +} + +static struct crypto_alg ecb_aes_alg = { + .cra_name = "ecb(aes)", + .cra_driver_name = "ecb-aes-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s390_aes_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .setkey = ecb_aes_set_key, + .encrypt = ecb_aes_encrypt, + .decrypt = ecb_aes_decrypt, + } + } +}; + +static int cbc_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, + unsigned int key_len) +{ + struct s390_aes_ctx *sctx = crypto_tfm_ctx(tfm); + + switch (key_len) { case 16: - ret = crypt_s390_kmc(KMC_AES_128_ENCRYPT, &sctx->iv, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); + sctx->enc = KMC_AES_128_ENCRYPT; + sctx->dec = KMC_AES_128_DECRYPT; break; case 24: - ret = crypt_s390_kmc(KMC_AES_192_ENCRYPT, &sctx->iv, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); + sctx->enc = KMC_AES_192_ENCRYPT; + sctx->dec = KMC_AES_192_DECRYPT; break; case 32: - ret = crypt_s390_kmc(KMC_AES_256_ENCRYPT, &sctx->iv, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); + sctx->enc = KMC_AES_256_ENCRYPT; + sctx->dec = KMC_AES_256_DECRYPT; break; } - memcpy(desc->info, &sctx->iv, AES_BLOCK_SIZE); - return nbytes; + return aes_set_key(tfm, in_key, key_len); } -static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out, - const u8 *in, unsigned int nbytes) +static int cbc_aes_crypt(struct blkcipher_desc *desc, long func, void *param, + struct blkcipher_walk *walk) { - struct s390_aes_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; + int ret = blkcipher_walk_virt(desc, walk); + unsigned int nbytes = walk->nbytes; - /* only use complete blocks */ - nbytes &= ~(AES_BLOCK_SIZE - 1); + if (!nbytes) + goto out; - memcpy(&sctx->iv, desc->info, AES_BLOCK_SIZE); - switch (sctx->key_len) { - case 16: - ret = crypt_s390_kmc(KMC_AES_128_DECRYPT, &sctx->iv, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); - break; - case 24: - ret = crypt_s390_kmc(KMC_AES_192_DECRYPT, &sctx->iv, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); - break; - case 32: - ret = crypt_s390_kmc(KMC_AES_256_DECRYPT, &sctx->iv, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); - break; - } - return nbytes; + memcpy(param, walk->iv, AES_BLOCK_SIZE); + do { + /* only use complete blocks */ + unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1); + u8 *out = walk->dst.virt.addr; + u8 *in = walk->src.virt.addr; + + ret = crypt_s390_kmc(func, param, out, in, n); + BUG_ON((ret < 0) || (ret != n)); + + nbytes &= AES_BLOCK_SIZE - 1; + ret = blkcipher_walk_done(desc, walk, nbytes); + } while ((nbytes = walk->nbytes)); + memcpy(walk->iv, param, AES_BLOCK_SIZE); + +out: + return ret; } +static int cbc_aes_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; -static struct crypto_alg aes_alg = { - .cra_name = "aes", - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + blkcipher_walk_init(&walk, dst, src, nbytes); + return cbc_aes_crypt(desc, sctx->enc, sctx->iv, &walk); +} + +static int cbc_aes_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct s390_aes_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; + + blkcipher_walk_init(&walk, dst, src, nbytes); + return cbc_aes_crypt(desc, sctx->dec, sctx->iv, &walk); +} + +static struct crypto_alg cbc_aes_alg = { + .cra_name = "cbc(aes)", + .cra_driver_name = "cbc-aes-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_aes_ctx), + .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(aes_alg.cra_list), + .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list), .cra_u = { - .cipher = { - .cia_min_keysize = AES_MIN_KEY_SIZE, - .cia_max_keysize = AES_MAX_KEY_SIZE, - .cia_setkey = aes_set_key, - .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt, - .cia_encrypt_ecb = aes_encrypt_ecb, - .cia_decrypt_ecb = aes_decrypt_ecb, - .cia_encrypt_cbc = aes_encrypt_cbc, - .cia_decrypt_cbc = aes_decrypt_cbc, + .blkcipher = { + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = cbc_aes_set_key, + .encrypt = cbc_aes_encrypt, + .decrypt = cbc_aes_decrypt, } } }; @@ -256,13 +332,40 @@ static int __init aes_init(void) return -ENOSYS; ret = crypto_register_alg(&aes_alg); - if (ret != 0) - printk(KERN_INFO "crypt_s390: aes_s390 couldn't be loaded.\n"); + if (ret != 0) { + printk(KERN_INFO "crypt_s390: aes-s390 couldn't be loaded.\n"); + goto aes_err; + } + + ret = crypto_register_alg(&ecb_aes_alg); + if (ret != 0) { + printk(KERN_INFO + "crypt_s390: ecb-aes-s390 couldn't be loaded.\n"); + goto ecb_aes_err; + } + + ret = crypto_register_alg(&cbc_aes_alg); + if (ret != 0) { + printk(KERN_INFO + "crypt_s390: cbc-aes-s390 couldn't be loaded.\n"); + goto cbc_aes_err; + } + +out: return ret; + +cbc_aes_err: + crypto_unregister_alg(&ecb_aes_alg); +ecb_aes_err: + crypto_unregister_alg(&aes_alg); +aes_err: + goto out; } static void __exit aes_fini(void) { + crypto_unregister_alg(&cbc_aes_alg); + crypto_unregister_alg(&ecb_aes_alg); crypto_unregister_alg(&aes_alg); } diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h index d1c259a7fe33..2b137089f625 100644 --- a/arch/s390/crypto/crypt_s390.h +++ b/arch/s390/crypto/crypt_s390.h @@ -20,6 +20,9 @@ #define CRYPT_S390_OP_MASK 0xFF00 #define CRYPT_S390_FUNC_MASK 0x00FF +#define CRYPT_S390_PRIORITY 300 +#define CRYPT_S390_COMPOSITE_PRIORITY 400 + /* s930 cryptographic operations */ enum crypt_s390_operations { CRYPT_S390_KM = 0x0100, @@ -102,63 +105,6 @@ struct crypt_s390_query_status { }; /* - * Standard fixup and ex_table sections for crypt_s390 inline functions. - * label 0: the s390 crypto operation - * label 1: just after 1 to catch illegal operation exception - * (unsupported model) - * label 6: the return point after fixup - * label 7: set error value if exception _in_ crypto operation - * label 8: set error value if illegal operation exception - * [ret] is the variable to receive the error code - * [ERR] is the error code value - */ -#ifndef CONFIG_64BIT -#define __crypt_s390_fixup \ - ".section .fixup,\"ax\" \n" \ - "7: lhi %0,%h[e1] \n" \ - " bras 1,9f \n" \ - " .long 6b \n" \ - "8: lhi %0,%h[e2] \n" \ - " bras 1,9f \n" \ - " .long 6b \n" \ - "9: l 1,0(1) \n" \ - " br 1 \n" \ - ".previous \n" \ - ".section __ex_table,\"a\" \n" \ - " .align 4 \n" \ - " .long 0b,7b \n" \ - " .long 1b,8b \n" \ - ".previous" -#else /* CONFIG_64BIT */ -#define __crypt_s390_fixup \ - ".section .fixup,\"ax\" \n" \ - "7: lhi %0,%h[e1] \n" \ - " jg 6b \n" \ - "8: lhi %0,%h[e2] \n" \ - " jg 6b \n" \ - ".previous\n" \ - ".section __ex_table,\"a\" \n" \ - " .align 8 \n" \ - " .quad 0b,7b \n" \ - " .quad 1b,8b \n" \ - ".previous" -#endif /* CONFIG_64BIT */ - -/* - * Standard code for setting the result of s390 crypto instructions. - * %0: the register which will receive the result - * [result]: the register containing the result (e.g. second operand length - * to compute number of processed bytes]. - */ -#ifndef CONFIG_64BIT -#define __crypt_s390_set_result \ - " lr %0,%[result] \n" -#else /* CONFIG_64BIT */ -#define __crypt_s390_set_result \ - " lgr %0,%[result] \n" -#endif - -/* * Executes the KM (CIPHER MESSAGE) operation of the CPU. * @param func: the function code passed to KM; see crypt_s390_km_func * @param param: address of parameter block; see POP for details on each func @@ -173,28 +119,24 @@ crypt_s390_km(long func, void* param, u8* dest, const u8* src, long src_len) { register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; register void* __param asm("1") = param; - register u8* __dest asm("4") = dest; register const u8* __src asm("2") = src; register long __src_len asm("3") = src_len; + register u8* __dest asm("4") = dest; int ret; - ret = 0; - __asm__ __volatile__ ( - "0: .insn rre,0xB92E0000,%1,%2 \n" /* KM opcode */ + asm volatile( + "0: .insn rre,0xb92e0000,%3,%1 \n" /* KM opcode */ "1: brc 1,0b \n" /* handle partial completion */ - __crypt_s390_set_result - "6: \n" - __crypt_s390_fixup - : "+d" (ret), "+a" (__dest), "+a" (__src), - [result] "+d" (__src_len) - : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), - "a" (__param) - : "cc", "memory" - ); - if (ret >= 0 && func & CRYPT_S390_FUNC_MASK){ - ret = src_len - ret; - } - return ret; + " ahi %0,%h7\n" + "2: ahi %0,%h8\n" + "3:\n" + EX_TABLE(0b,3b) EX_TABLE(1b,2b) + : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest) + : "d" (__func), "a" (__param), "0" (-EFAULT), + "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); + if (ret < 0) + return ret; + return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } /* @@ -212,28 +154,24 @@ crypt_s390_kmc(long func, void* param, u8* dest, const u8* src, long src_len) { register long __func asm("0") = func & CRYPT_S390_FUNC_MASK; register void* __param asm("1") = param; - register u8* __dest asm("4") = dest; register const u8* __src asm("2") = src; register long __src_len asm("3") = src_len; + register u8* __dest asm("4") = dest; int ret; - ret = 0; - __asm__ __volatile__ ( - "0: .insn rre,0xB92F0000,%1,%2 \n" /* KMC opcode */ + asm volatile( + "0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */ "1: brc 1,0b \n" /* handle partial completion */ - __crypt_s390_set_result - "6: \n" - __crypt_s390_fixup - : "+d" (ret), "+a" (__dest), "+a" (__src), - [result] "+d" (__src_len) - : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), - "a" (__param) - : "cc", "memory" - ); - if (ret >= 0 && func & CRYPT_S390_FUNC_MASK){ - ret = src_len - ret; - } - return ret; + " ahi %0,%h7\n" + "2: ahi %0,%h8\n" + "3:\n" + EX_TABLE(0b,3b) EX_TABLE(1b,2b) + : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest) + : "d" (__func), "a" (__param), "0" (-EFAULT), + "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); + if (ret < 0) + return ret; + return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } /* @@ -255,22 +193,19 @@ crypt_s390_kimd(long func, void* param, const u8* src, long src_len) register long __src_len asm("3") = src_len; int ret; - ret = 0; - __asm__ __volatile__ ( - "0: .insn rre,0xB93E0000,%1,%1 \n" /* KIMD opcode */ - "1: brc 1,0b \n" /* handle partical completion */ - __crypt_s390_set_result - "6: \n" - __crypt_s390_fixup - : "+d" (ret), "+a" (__src), [result] "+d" (__src_len) - : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), - "a" (__param) - : "cc", "memory" - ); - if (ret >= 0 && (func & CRYPT_S390_FUNC_MASK)){ - ret = src_len - ret; - } - return ret; + asm volatile( + "0: .insn rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */ + "1: brc 1,0b \n" /* handle partial completion */ + " ahi %0,%h6\n" + "2: ahi %0,%h7\n" + "3:\n" + EX_TABLE(0b,3b) EX_TABLE(1b,2b) + : "=d" (ret), "+a" (__src), "+d" (__src_len) + : "d" (__func), "a" (__param), "0" (-EFAULT), + "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); + if (ret < 0) + return ret; + return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } /* @@ -291,22 +226,19 @@ crypt_s390_klmd(long func, void* param, const u8* src, long src_len) register long __src_len asm("3") = src_len; int ret; - ret = 0; - __asm__ __volatile__ ( - "0: .insn rre,0xB93F0000,%1,%1 \n" /* KLMD opcode */ - "1: brc 1,0b \n" /* handle partical completion */ - __crypt_s390_set_result - "6: \n" - __crypt_s390_fixup - : "+d" (ret), "+a" (__src), [result] "+d" (__src_len) - : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), - "a" (__param) - : "cc", "memory" - ); - if (ret >= 0 && func & CRYPT_S390_FUNC_MASK){ - ret = src_len - ret; - } - return ret; + asm volatile( + "0: .insn rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */ + "1: brc 1,0b \n" /* handle partial completion */ + " ahi %0,%h6\n" + "2: ahi %0,%h7\n" + "3:\n" + EX_TABLE(0b,3b) EX_TABLE(1b,2b) + : "=d" (ret), "+a" (__src), "+d" (__src_len) + : "d" (__func), "a" (__param), "0" (-EFAULT), + "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); + if (ret < 0) + return ret; + return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } /* @@ -328,22 +260,19 @@ crypt_s390_kmac(long func, void* param, const u8* src, long src_len) register long __src_len asm("3") = src_len; int ret; - ret = 0; - __asm__ __volatile__ ( - "0: .insn rre,0xB91E0000,%5,%5 \n" /* KMAC opcode */ - "1: brc 1,0b \n" /* handle partical completion */ - __crypt_s390_set_result - "6: \n" - __crypt_s390_fixup - : "+d" (ret), "+a" (__src), [result] "+d" (__src_len) - : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func), - "a" (__param) - : "cc", "memory" - ); - if (ret >= 0 && func & CRYPT_S390_FUNC_MASK){ - ret = src_len - ret; - } - return ret; + asm volatile( + "0: .insn rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */ + "1: brc 1,0b \n" /* handle partial completion */ + " ahi %0,%h6\n" + "2: ahi %0,%h7\n" + "3:\n" + EX_TABLE(0b,3b) EX_TABLE(1b,2b) + : "=d" (ret), "+a" (__src), "+d" (__src_len) + : "d" (__func), "a" (__param), "0" (-EFAULT), + "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory"); + if (ret < 0) + return ret; + return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len; } /** diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c index b3f7496a79b4..2aba04852fe3 100644 --- a/arch/s390/crypto/des_s390.c +++ b/arch/s390/crypto/des_s390.c @@ -13,9 +13,10 @@ * (at your option) any later version. * */ + +#include <crypto/algapi.h> #include <linux/init.h> #include <linux/module.h> -#include <linux/crypto.h> #include "crypt_s390.h" #include "crypto_des.h" @@ -45,9 +46,10 @@ struct crypt_s390_des3_192_ctx { }; static int des_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen, u32 *flags) + unsigned int keylen) { struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm); + u32 *flags = &tfm->crt_flags; int ret; /* test if key is valid (not a weak key) */ @@ -71,85 +73,159 @@ static void des_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) crypt_s390_km(KM_DEA_DECRYPT, dctx->key, out, in, DES_BLOCK_SIZE); } -static unsigned int des_encrypt_ecb(const struct cipher_desc *desc, u8 *out, - const u8 *in, unsigned int nbytes) +static struct crypto_alg des_alg = { + .cra_name = "des", + .cra_driver_name = "des-s390", + .cra_priority = CRYPT_S390_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_s390_des_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(des_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = DES_KEY_SIZE, + .cia_max_keysize = DES_KEY_SIZE, + .cia_setkey = des_setkey, + .cia_encrypt = des_encrypt, + .cia_decrypt = des_decrypt, + } + } +}; + +static int ecb_desall_crypt(struct blkcipher_desc *desc, long func, + void *param, struct blkcipher_walk *walk) { - struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; + int ret = blkcipher_walk_virt(desc, walk); + unsigned int nbytes; + + while ((nbytes = walk->nbytes)) { + /* only use complete blocks */ + unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1); + u8 *out = walk->dst.virt.addr; + u8 *in = walk->src.virt.addr; - /* only use complete blocks */ - nbytes &= ~(DES_BLOCK_SIZE - 1); - ret = crypt_s390_km(KM_DEA_ENCRYPT, sctx->key, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); + ret = crypt_s390_km(func, param, out, in, n); + BUG_ON((ret < 0) || (ret != n)); - return nbytes; + nbytes &= DES_BLOCK_SIZE - 1; + ret = blkcipher_walk_done(desc, walk, nbytes); + } + + return ret; } -static unsigned int des_decrypt_ecb(const struct cipher_desc *desc, u8 *out, - const u8 *in, unsigned int nbytes) +static int cbc_desall_crypt(struct blkcipher_desc *desc, long func, + void *param, struct blkcipher_walk *walk) { - struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; + int ret = blkcipher_walk_virt(desc, walk); + unsigned int nbytes = walk->nbytes; + + if (!nbytes) + goto out; + + memcpy(param, walk->iv, DES_BLOCK_SIZE); + do { + /* only use complete blocks */ + unsigned int n = nbytes & ~(DES_BLOCK_SIZE - 1); + u8 *out = walk->dst.virt.addr; + u8 *in = walk->src.virt.addr; - /* only use complete blocks */ - nbytes &= ~(DES_BLOCK_SIZE - 1); - ret = crypt_s390_km(KM_DEA_DECRYPT, sctx->key, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); + ret = crypt_s390_kmc(func, param, out, in, n); + BUG_ON((ret < 0) || (ret != n)); - return nbytes; + nbytes &= DES_BLOCK_SIZE - 1; + ret = blkcipher_walk_done(desc, walk, nbytes); + } while ((nbytes = walk->nbytes)); + memcpy(walk->iv, param, DES_BLOCK_SIZE); + +out: + return ret; } -static unsigned int des_encrypt_cbc(const struct cipher_desc *desc, u8 *out, - const u8 *in, unsigned int nbytes) +static int ecb_des_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) { - struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; + struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - /* only use complete blocks */ - nbytes &= ~(DES_BLOCK_SIZE - 1); + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_desall_crypt(desc, KM_DEA_ENCRYPT, sctx->key, &walk); +} - memcpy(sctx->iv, desc->info, DES_BLOCK_SIZE); - ret = crypt_s390_kmc(KMC_DEA_ENCRYPT, &sctx->iv, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); +static int ecb_des_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - memcpy(desc->info, sctx->iv, DES_BLOCK_SIZE); - return nbytes; + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_desall_crypt(desc, KM_DEA_DECRYPT, sctx->key, &walk); } -static unsigned int des_decrypt_cbc(const struct cipher_desc *desc, u8 *out, - const u8 *in, unsigned int nbytes) +static struct crypto_alg ecb_des_alg = { + .cra_name = "ecb(des)", + .cra_driver_name = "ecb-des-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = DES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_s390_des_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(ecb_des_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .setkey = des_setkey, + .encrypt = ecb_des_encrypt, + .decrypt = ecb_des_decrypt, + } + } +}; + +static int cbc_des_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) { - struct crypt_s390_des_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; + struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - /* only use complete blocks */ - nbytes &= ~(DES_BLOCK_SIZE - 1); + blkcipher_walk_init(&walk, dst, src, nbytes); + return cbc_desall_crypt(desc, KMC_DEA_ENCRYPT, sctx->iv, &walk); +} - memcpy(&sctx->iv, desc->info, DES_BLOCK_SIZE); - ret = crypt_s390_kmc(KMC_DEA_DECRYPT, &sctx->iv, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); +static int cbc_des_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + struct crypt_s390_des_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - return nbytes; + blkcipher_walk_init(&walk, dst, src, nbytes); + return cbc_desall_crypt(desc, KMC_DEA_DECRYPT, sctx->iv, &walk); } -static struct crypto_alg des_alg = { - .cra_name = "des", - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, +static struct crypto_alg cbc_des_alg = { + .cra_name = "cbc(des)", + .cra_driver_name = "cbc-des-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypt_s390_des_ctx), + .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(des_alg.cra_list), + .cra_list = LIST_HEAD_INIT(cbc_des_alg.cra_list), .cra_u = { - .cipher = { - .cia_min_keysize = DES_KEY_SIZE, - .cia_max_keysize = DES_KEY_SIZE, - .cia_setkey = des_setkey, - .cia_encrypt = des_encrypt, - .cia_decrypt = des_decrypt, - .cia_encrypt_ecb = des_encrypt_ecb, - .cia_decrypt_ecb = des_decrypt_ecb, - .cia_encrypt_cbc = des_encrypt_cbc, - .cia_decrypt_cbc = des_decrypt_cbc, + .blkcipher = { + .min_keysize = DES_KEY_SIZE, + .max_keysize = DES_KEY_SIZE, + .ivsize = DES_BLOCK_SIZE, + .setkey = des_setkey, + .encrypt = cbc_des_encrypt, + .decrypt = cbc_des_decrypt, } } }; @@ -167,11 +243,12 @@ static struct crypto_alg des_alg = { * */ static int des3_128_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen, u32 *flags) + unsigned int keylen) { int i, ret; struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm); - const u8* temp_key = key; + const u8 *temp_key = key; + u32 *flags = &tfm->crt_flags; if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE))) { *flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED; @@ -202,89 +279,111 @@ static void des3_128_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) DES3_128_BLOCK_SIZE); } -static unsigned int des3_128_encrypt_ecb(const struct cipher_desc *desc, - u8 *out, const u8 *in, - unsigned int nbytes) -{ - struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; +static struct crypto_alg des3_128_alg = { + .cra_name = "des3_ede128", + .cra_driver_name = "des3_ede128-s390", + .cra_priority = CRYPT_S390_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES3_128_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(des3_128_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = DES3_128_KEY_SIZE, + .cia_max_keysize = DES3_128_KEY_SIZE, + .cia_setkey = des3_128_setkey, + .cia_encrypt = des3_128_encrypt, + .cia_decrypt = des3_128_decrypt, + } + } +}; - /* only use complete blocks */ - nbytes &= ~(DES3_128_BLOCK_SIZE - 1); - ret = crypt_s390_km(KM_TDEA_128_ENCRYPT, sctx->key, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); +static int ecb_des3_128_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - return nbytes; + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_desall_crypt(desc, KM_TDEA_128_ENCRYPT, sctx->key, &walk); } -static unsigned int des3_128_decrypt_ecb(const struct cipher_desc *desc, - u8 *out, const u8 *in, - unsigned int nbytes) +static int ecb_des3_128_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) { - struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; + struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - /* only use complete blocks */ - nbytes &= ~(DES3_128_BLOCK_SIZE - 1); - ret = crypt_s390_km(KM_TDEA_128_DECRYPT, sctx->key, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); - - return nbytes; + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_desall_crypt(desc, KM_TDEA_128_DECRYPT, sctx->key, &walk); } -static unsigned int des3_128_encrypt_cbc(const struct cipher_desc *desc, - u8 *out, const u8 *in, - unsigned int nbytes) -{ - struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; - - /* only use complete blocks */ - nbytes &= ~(DES3_128_BLOCK_SIZE - 1); +static struct crypto_alg ecb_des3_128_alg = { + .cra_name = "ecb(des3_ede128)", + .cra_driver_name = "ecb-des3_ede128-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = DES3_128_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT( + ecb_des3_128_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES3_128_KEY_SIZE, + .max_keysize = DES3_128_KEY_SIZE, + .setkey = des3_128_setkey, + .encrypt = ecb_des3_128_encrypt, + .decrypt = ecb_des3_128_decrypt, + } + } +}; - memcpy(sctx->iv, desc->info, DES3_128_BLOCK_SIZE); - ret = crypt_s390_kmc(KMC_TDEA_128_ENCRYPT, &sctx->iv, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); +static int cbc_des3_128_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - memcpy(desc->info, sctx->iv, DES3_128_BLOCK_SIZE); - return nbytes; + blkcipher_walk_init(&walk, dst, src, nbytes); + return cbc_desall_crypt(desc, KMC_TDEA_128_ENCRYPT, sctx->iv, &walk); } -static unsigned int des3_128_decrypt_cbc(const struct cipher_desc *desc, - u8 *out, const u8 *in, - unsigned int nbytes) +static int cbc_des3_128_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) { - struct crypt_s390_des3_128_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; - - /* only use complete blocks */ - nbytes &= ~(DES3_128_BLOCK_SIZE - 1); - - memcpy(&sctx->iv, desc->info, DES3_128_BLOCK_SIZE); - ret = crypt_s390_kmc(KMC_TDEA_128_DECRYPT, &sctx->iv, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); + struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - return nbytes; + blkcipher_walk_init(&walk, dst, src, nbytes); + return cbc_desall_crypt(desc, KMC_TDEA_128_DECRYPT, sctx->iv, &walk); } -static struct crypto_alg des3_128_alg = { - .cra_name = "des3_ede128", - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, +static struct crypto_alg cbc_des3_128_alg = { + .cra_name = "cbc(des3_ede128)", + .cra_driver_name = "cbc-des3_ede128-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = DES3_128_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx), + .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(des3_128_alg.cra_list), + .cra_list = LIST_HEAD_INIT( + cbc_des3_128_alg.cra_list), .cra_u = { - .cipher = { - .cia_min_keysize = DES3_128_KEY_SIZE, - .cia_max_keysize = DES3_128_KEY_SIZE, - .cia_setkey = des3_128_setkey, - .cia_encrypt = des3_128_encrypt, - .cia_decrypt = des3_128_decrypt, - .cia_encrypt_ecb = des3_128_encrypt_ecb, - .cia_decrypt_ecb = des3_128_decrypt_ecb, - .cia_encrypt_cbc = des3_128_encrypt_cbc, - .cia_decrypt_cbc = des3_128_decrypt_cbc, + .blkcipher = { + .min_keysize = DES3_128_KEY_SIZE, + .max_keysize = DES3_128_KEY_SIZE, + .ivsize = DES3_128_BLOCK_SIZE, + .setkey = des3_128_setkey, + .encrypt = cbc_des3_128_encrypt, + .decrypt = cbc_des3_128_decrypt, } } }; @@ -303,11 +402,12 @@ static struct crypto_alg des3_128_alg = { * */ static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen, u32 *flags) + unsigned int keylen) { int i, ret; struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm); - const u8* temp_key = key; + const u8 *temp_key = key; + u32 *flags = &tfm->crt_flags; if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) && memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2], @@ -341,89 +441,111 @@ static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) DES3_192_BLOCK_SIZE); } -static unsigned int des3_192_encrypt_ecb(const struct cipher_desc *desc, - u8 *out, const u8 *in, - unsigned int nbytes) -{ - struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; +static struct crypto_alg des3_192_alg = { + .cra_name = "des3_ede", + .cra_driver_name = "des3_ede-s390", + .cra_priority = CRYPT_S390_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = DES3_192_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx), + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = DES3_192_KEY_SIZE, + .cia_max_keysize = DES3_192_KEY_SIZE, + .cia_setkey = des3_192_setkey, + .cia_encrypt = des3_192_encrypt, + .cia_decrypt = des3_192_decrypt, + } + } +}; - /* only use complete blocks */ - nbytes &= ~(DES3_192_BLOCK_SIZE - 1); - ret = crypt_s390_km(KM_TDEA_192_ENCRYPT, sctx->key, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); +static int ecb_des3_192_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - return nbytes; + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_desall_crypt(desc, KM_TDEA_192_ENCRYPT, sctx->key, &walk); } -static unsigned int des3_192_decrypt_ecb(const struct cipher_desc *desc, - u8 *out, const u8 *in, - unsigned int nbytes) +static int ecb_des3_192_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) { - struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; - - /* only use complete blocks */ - nbytes &= ~(DES3_192_BLOCK_SIZE - 1); - ret = crypt_s390_km(KM_TDEA_192_DECRYPT, sctx->key, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); + struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - return nbytes; + blkcipher_walk_init(&walk, dst, src, nbytes); + return ecb_desall_crypt(desc, KM_TDEA_192_DECRYPT, sctx->key, &walk); } -static unsigned int des3_192_encrypt_cbc(const struct cipher_desc *desc, - u8 *out, const u8 *in, - unsigned int nbytes) -{ - struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; - - /* only use complete blocks */ - nbytes &= ~(DES3_192_BLOCK_SIZE - 1); +static struct crypto_alg ecb_des3_192_alg = { + .cra_name = "ecb(des3_ede)", + .cra_driver_name = "ecb-des3_ede-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = DES3_192_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx), + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT( + ecb_des3_192_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = DES3_192_KEY_SIZE, + .max_keysize = DES3_192_KEY_SIZE, + .setkey = des3_192_setkey, + .encrypt = ecb_des3_192_encrypt, + .decrypt = ecb_des3_192_decrypt, + } + } +}; - memcpy(sctx->iv, desc->info, DES3_192_BLOCK_SIZE); - ret = crypt_s390_kmc(KMC_TDEA_192_ENCRYPT, &sctx->iv, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); +static int cbc_des3_192_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) +{ + struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - memcpy(desc->info, sctx->iv, DES3_192_BLOCK_SIZE); - return nbytes; + blkcipher_walk_init(&walk, dst, src, nbytes); + return cbc_desall_crypt(desc, KMC_TDEA_192_ENCRYPT, sctx->iv, &walk); } -static unsigned int des3_192_decrypt_cbc(const struct cipher_desc *desc, - u8 *out, const u8 *in, - unsigned int nbytes) +static int cbc_des3_192_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes) { - struct crypt_s390_des3_192_ctx *sctx = crypto_tfm_ctx(desc->tfm); - int ret; + struct crypt_s390_des3_192_ctx *sctx = crypto_blkcipher_ctx(desc->tfm); + struct blkcipher_walk walk; - /* only use complete blocks */ - nbytes &= ~(DES3_192_BLOCK_SIZE - 1); - - memcpy(&sctx->iv, desc->info, DES3_192_BLOCK_SIZE); - ret = crypt_s390_kmc(KMC_TDEA_192_DECRYPT, &sctx->iv, out, in, nbytes); - BUG_ON((ret < 0) || (ret != nbytes)); - - return nbytes; + blkcipher_walk_init(&walk, dst, src, nbytes); + return cbc_desall_crypt(desc, KMC_TDEA_192_DECRYPT, sctx->iv, &walk); } -static struct crypto_alg des3_192_alg = { - .cra_name = "des3_ede", - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, +static struct crypto_alg cbc_des3_192_alg = { + .cra_name = "cbc(des3_ede)", + .cra_driver_name = "cbc-des3_ede-s390", + .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, .cra_blocksize = DES3_192_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx), + .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list), + .cra_list = LIST_HEAD_INIT( + cbc_des3_192_alg.cra_list), .cra_u = { - .cipher = { - .cia_min_keysize = DES3_192_KEY_SIZE, - .cia_max_keysize = DES3_192_KEY_SIZE, - .cia_setkey = des3_192_setkey, - .cia_encrypt = des3_192_encrypt, - .cia_decrypt = des3_192_decrypt, - .cia_encrypt_ecb = des3_192_encrypt_ecb, - .cia_decrypt_ecb = des3_192_decrypt_ecb, - .cia_encrypt_cbc = des3_192_encrypt_cbc, - .cia_decrypt_cbc = des3_192_decrypt_cbc, + .blkcipher = { + .min_keysize = DES3_192_KEY_SIZE, + .max_keysize = DES3_192_KEY_SIZE, + .ivsize = DES3_192_BLOCK_SIZE, + .setkey = des3_192_setkey, + .encrypt = cbc_des3_192_encrypt, + .decrypt = cbc_des3_192_decrypt, } } }; @@ -437,22 +559,69 @@ static int init(void) !crypt_s390_func_available(KM_TDEA_192_ENCRYPT)) return -ENOSYS; - ret |= (crypto_register_alg(&des_alg) == 0) ? 0:1; - ret |= (crypto_register_alg(&des3_128_alg) == 0) ? 0:2; - ret |= (crypto_register_alg(&des3_192_alg) == 0) ? 0:4; - if (ret) { - crypto_unregister_alg(&des3_192_alg); - crypto_unregister_alg(&des3_128_alg); - crypto_unregister_alg(&des_alg); - return -EEXIST; - } - return 0; + ret = crypto_register_alg(&des_alg); + if (ret) + goto des_err; + ret = crypto_register_alg(&ecb_des_alg); + if (ret) + goto ecb_des_err; + ret = crypto_register_alg(&cbc_des_alg); + if (ret) + goto cbc_des_err; + + ret = crypto_register_alg(&des3_128_alg); + if (ret) + goto des3_128_err; + ret = crypto_register_alg(&ecb_des3_128_alg); + if (ret) + goto ecb_des3_128_err; + ret = crypto_register_alg(&cbc_des3_128_alg); + if (ret) + goto cbc_des3_128_err; + + ret = crypto_register_alg(&des3_192_alg); + if (ret) + goto des3_192_err; + ret = crypto_register_alg(&ecb_des3_192_alg); + if (ret) + goto ecb_des3_192_err; + ret = crypto_register_alg(&cbc_des3_192_alg); + if (ret) + goto cbc_des3_192_err; + +out: + return ret; + +cbc_des3_192_err: + crypto_unregister_alg(&ecb_des3_192_alg); +ecb_des3_192_err: + crypto_unregister_alg(&des3_192_alg); +des3_192_err: + crypto_unregister_alg(&cbc_des3_128_alg); +cbc_des3_128_err: + crypto_unregister_alg(&ecb_des3_128_alg); +ecb_des3_128_err: + crypto_unregister_alg(&des3_128_alg); +des3_128_err: + crypto_unregister_alg(&cbc_des_alg); +cbc_des_err: + crypto_unregister_alg(&ecb_des_alg); +ecb_des_err: + crypto_unregister_alg(&des_alg); +des_err: + goto out; } static void __exit fini(void) { + crypto_unregister_alg(&cbc_des3_192_alg); + crypto_unregister_alg(&ecb_des3_192_alg); crypto_unregister_alg(&des3_192_alg); + crypto_unregister_alg(&cbc_des3_128_alg); + crypto_unregister_alg(&ecb_des3_128_alg); crypto_unregister_alg(&des3_128_alg); + crypto_unregister_alg(&cbc_des_alg); + crypto_unregister_alg(&ecb_des_alg); crypto_unregister_alg(&des_alg); } diff --git a/arch/s390/crypto/sha1_s390.c b/arch/s390/crypto/sha1_s390.c index 9d34a35b1aa5..49ca8690ee39 100644 --- a/arch/s390/crypto/sha1_s390.c +++ b/arch/s390/crypto/sha1_s390.c @@ -126,6 +126,8 @@ static void sha1_final(struct crypto_tfm *tfm, u8 *out) static struct crypto_alg alg = { .cra_name = "sha1", + .cra_driver_name = "sha1-s390", + .cra_priority = CRYPT_S390_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_DIGEST, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct crypt_s390_sha1_ctx), diff --git a/arch/s390/crypto/sha256_s390.c b/arch/s390/crypto/sha256_s390.c index f573df30f31d..8e4e67503fe7 100644 --- a/arch/s390/crypto/sha256_s390.c +++ b/arch/s390/crypto/sha256_s390.c @@ -127,6 +127,8 @@ static void sha256_final(struct crypto_tfm *tfm, u8 *out) static struct crypto_alg alg = { .cra_name = "sha256", + .cra_driver_name = "sha256-s390", + .cra_priority = CRYPT_S390_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_DIGEST, .cra_blocksize = SHA256_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_sha256_ctx), diff --git a/arch/s390/defconfig b/arch/s390/defconfig index f1d4591eddbb..35da53986b1b 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -428,6 +428,7 @@ CONFIG_S390_TAPE_34XX=m # CONFIG_VMLOGRDR is not set # CONFIG_VMCP is not set # CONFIG_MONREADER is not set +CONFIG_MONWRITER=m # # Cryptographic devices diff --git a/arch/s390/hypfs/hypfs.h b/arch/s390/hypfs/hypfs.h index ea5567be00fc..f3dbd91965c6 100644 --- a/arch/s390/hypfs/hypfs.h +++ b/arch/s390/hypfs/hypfs.h @@ -1,5 +1,5 @@ /* - * fs/hypfs/hypfs.h + * arch/s390/hypfs/hypfs.h * Hypervisor filesystem for Linux on s390. * * Copyright (C) IBM Corp. 2006 diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c index 1785bce2b919..443fa377d9ff 100644 --- a/arch/s390/hypfs/hypfs_diag.c +++ b/arch/s390/hypfs/hypfs_diag.c @@ -1,5 +1,5 @@ /* - * fs/hypfs/hypfs_diag.c + * arch/s390/hypfs/hypfs_diag.c * Hypervisor filesystem for Linux on s390. Diag 204 and 224 * implementation. * @@ -333,22 +333,14 @@ static int diag204(unsigned long subcode, unsigned long size, void *addr) register unsigned long _subcode asm("0") = subcode; register unsigned long _size asm("1") = size; - asm volatile (" diag %2,%0,0x204\n" - "0: \n" ".section __ex_table,\"a\"\n" -#ifndef __s390x__ - " .align 4\n" - " .long 0b,0b\n" -#else - " .align 8\n" - " .quad 0b,0b\n" -#endif - ".previous":"+d" (_subcode), "+d"(_size) - :"d"(addr) - :"memory"); + asm volatile( + " diag %2,%0,0x204\n" + "0:\n" + EX_TABLE(0b,0b) + : "+d" (_subcode), "+d" (_size) : "d" (addr) : "memory"); if (_subcode) return -1; - else - return _size; + return _size; } /* @@ -403,7 +395,8 @@ static void *diag204_get_buffer(enum diag204_format fmt, int *pages) *pages = 1; return diag204_alloc_rbuf(); } else {/* INFO_EXT */ - *pages = diag204(SUBC_RSI | INFO_EXT, 0, NULL); + *pages = diag204((unsigned long)SUBC_RSI | + (unsigned long)INFO_EXT, 0, NULL); if (*pages <= 0) return ERR_PTR(-ENOSYS); else @@ -432,12 +425,14 @@ static int diag204_probe(void) buf = diag204_get_buffer(INFO_EXT, &pages); if (!IS_ERR(buf)) { - if (diag204(SUBC_STIB7 | INFO_EXT, pages, buf) >= 0) { + if (diag204((unsigned long)SUBC_STIB7 | + (unsigned long)INFO_EXT, pages, buf) >= 0) { diag204_store_sc = SUBC_STIB7; diag204_info_type = INFO_EXT; goto out; } - if (diag204(SUBC_STIB6 | INFO_EXT, pages, buf) >= 0) { + if (diag204((unsigned long)SUBC_STIB6 | + (unsigned long)INFO_EXT, pages, buf) >= 0) { diag204_store_sc = SUBC_STIB7; diag204_info_type = INFO_EXT; goto out; @@ -452,7 +447,8 @@ static int diag204_probe(void) rc = PTR_ERR(buf); goto fail_alloc; } - if (diag204(SUBC_STIB4 | INFO_SIMPLE, pages, buf) >= 0) { + if (diag204((unsigned long)SUBC_STIB4 | + (unsigned long)INFO_SIMPLE, pages, buf) >= 0) { diag204_store_sc = SUBC_STIB4; diag204_info_type = INFO_SIMPLE; goto out; @@ -476,7 +472,8 @@ static void *diag204_store(void) buf = diag204_get_buffer(diag204_info_type, &pages); if (IS_ERR(buf)) goto out; - if (diag204(diag204_store_sc | diag204_info_type, pages, buf) < 0) + if (diag204((unsigned long)diag204_store_sc | + (unsigned long)diag204_info_type, pages, buf) < 0) return ERR_PTR(-ENOSYS); out: return buf; @@ -486,8 +483,7 @@ out: static void diag224(void *ptr) { - asm volatile(" diag %0,%1,0x224\n" - : :"d" (0), "d"(ptr) : "memory"); + asm volatile("diag %0,%1,0x224" : :"d" (0), "d"(ptr) : "memory"); } static int diag224_get_name_table(void) @@ -531,7 +527,7 @@ __init int hypfs_diag_init(void) return rc; } -__exit void hypfs_diag_exit(void) +void hypfs_diag_exit(void) { diag224_delete_name_table(); diag204_free_buffer(); diff --git a/arch/s390/hypfs/hypfs_diag.h b/arch/s390/hypfs/hypfs_diag.h index 793dea6b9bb6..256b384aebe1 100644 --- a/arch/s390/hypfs/hypfs_diag.h +++ b/arch/s390/hypfs/hypfs_diag.h @@ -1,5 +1,5 @@ /* - * fs/hypfs/hypfs_diag.h + * arch/s390/hypfs_diag.h * Hypervisor filesystem for Linux on s390. * * Copyright (C) IBM Corp. 2006 diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 18c091925ea5..cd702ae45d6d 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -1,5 +1,5 @@ /* - * fs/hypfs/inode.c + * arch/s390/hypfs/inode.c * Hypervisor filesystem for Linux on s390. * * Copyright (C) IBM Corp. 2006 @@ -91,7 +91,6 @@ static struct inode *hypfs_make_inode(struct super_block *sb, int mode) ret->i_mode = mode; ret->i_uid = hypfs_info->uid; ret->i_gid = hypfs_info->gid; - ret->i_blksize = PAGE_CACHE_SIZE; ret->i_blocks = 0; ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME; if (mode & S_IFDIR) @@ -104,13 +103,13 @@ static struct inode *hypfs_make_inode(struct super_block *sb, int mode) static void hypfs_drop_inode(struct inode *inode) { - kfree(inode->u.generic_ip); + kfree(inode->i_private); generic_delete_inode(inode); } static int hypfs_open(struct inode *inode, struct file *filp) { - char *data = filp->f_dentry->d_inode->u.generic_ip; + char *data = filp->f_dentry->d_inode->i_private; struct hypfs_sb_info *fs_info; if (filp->f_mode & FMODE_WRITE) { @@ -135,12 +134,20 @@ static int hypfs_open(struct inode *inode, struct file *filp) return 0; } -static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf, - size_t count, loff_t offset) +static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t offset) { char *data; size_t len; struct file *filp = iocb->ki_filp; + /* XXX: temporary */ + char __user *buf = iov[0].iov_base; + size_t count = iov[0].iov_len; + + if (nr_segs != 1) { + count = -EINVAL; + goto out; + } data = filp->private_data; len = strlen(data); @@ -159,12 +166,13 @@ static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf, out: return count; } -static ssize_t hypfs_aio_write(struct kiocb *iocb, const char __user *buf, - size_t count, loff_t pos) +static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long nr_segs, loff_t offset) { int rc; struct super_block *sb; struct hypfs_sb_info *fs_info; + size_t count = iov_length(iov, nr_segs); sb = iocb->ki_filp->f_dentry->d_inode->i_sb; fs_info = sb->s_fs_info; @@ -312,10 +320,12 @@ static void hypfs_kill_super(struct super_block *sb) { struct hypfs_sb_info *sb_info = sb->s_fs_info; - hypfs_delete_tree(sb->s_root); - hypfs_remove(sb_info->update_file); - kfree(sb->s_fs_info); - sb->s_fs_info = NULL; + if (sb->s_root) { + hypfs_delete_tree(sb->s_root); + hypfs_remove(sb_info->update_file); + kfree(sb->s_fs_info); + sb->s_fs_info = NULL; + } kill_litter_super(sb); } @@ -350,7 +360,7 @@ static struct dentry *hypfs_create_file(struct super_block *sb, parent->d_inode->i_nlink++; } else BUG(); - inode->u.generic_ip = data; + inode->i_private = data; d_instantiate(dentry, inode); dget(dentry); return dentry; diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 9a33ed6ca696..aa978978d3d1 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -6,7 +6,7 @@ EXTRA_AFLAGS := -traditional obj-y := bitmap.o traps.o time.o process.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - semaphore.o s390_ext.o debug.o profile.o irq.o reipl_diag.o + semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) @@ -24,6 +24,7 @@ obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \ obj-$(CONFIG_VIRT_TIMER) += vtime.o obj-$(CONFIG_STACKTRACE) += stacktrace.o +obj-$(CONFIG_KPROBES) += kprobes.o # Kexec part S390_KEXEC_OBJS := machine_kexec.o crash.o diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 785c9f70ac98..c46e3d48e410 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -544,10 +544,7 @@ sys32_execve(struct pt_regs regs) current->ptrace &= ~PT_DTRACE; task_unlock(current); current->thread.fp_regs.fpc=0; - __asm__ __volatile__ - ("sr 0,0\n\t" - "sfpc 0,0\n\t" - : : :"0"); + asm volatile("sfpc %0,0" : : "d" (0)); } putname(filename); out: @@ -708,7 +705,7 @@ asmlinkage long sys32_sendfile64(int out_fd, int in_fd, return ret; } -#ifdef CONFIG_SYSCTL +#ifdef CONFIG_SYSCTL_SYSCALL struct __sysctl_args32 { u32 name; int nlen; diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 4d53b2739357..4aabeeaa7cf7 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -4,97 +4,97 @@ * * Copyright (C) IBM Corp. 2000,2006 * Author(s): Gerhard Tonn (ton@de.ibm.com), -* Thomas Spatzier (tspat@de.ibm.com) -*/ +* Thomas Spatzier (tspat@de.ibm.com) +*/ - .globl sys32_exit_wrapper + .globl sys32_exit_wrapper sys32_exit_wrapper: lgfr %r2,%r2 # int jg sys_exit # branch to sys_exit - - .globl sys32_read_wrapper + + .globl sys32_read_wrapper sys32_read_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # char * llgfr %r4,%r4 # size_t jg sys32_read # branch to sys_read - .globl sys32_write_wrapper + .globl sys32_write_wrapper sys32_write_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # const char * llgfr %r4,%r4 # size_t jg sys32_write # branch to system call - .globl sys32_open_wrapper + .globl sys32_open_wrapper sys32_open_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int lgfr %r4,%r4 # int jg sys_open # branch to system call - .globl sys32_close_wrapper + .globl sys32_close_wrapper sys32_close_wrapper: llgfr %r2,%r2 # unsigned int jg sys_close # branch to system call - .globl sys32_creat_wrapper + .globl sys32_creat_wrapper sys32_creat_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int jg sys_creat # branch to system call - .globl sys32_link_wrapper + .globl sys32_link_wrapper sys32_link_wrapper: llgtr %r2,%r2 # const char * llgtr %r3,%r3 # const char * jg sys_link # branch to system call - .globl sys32_unlink_wrapper + .globl sys32_unlink_wrapper sys32_unlink_wrapper: llgtr %r2,%r2 # const char * jg sys_unlink # branch to system call - .globl sys32_chdir_wrapper + .globl sys32_chdir_wrapper sys32_chdir_wrapper: llgtr %r2,%r2 # const char * jg sys_chdir # branch to system call - .globl sys32_time_wrapper + .globl sys32_time_wrapper sys32_time_wrapper: llgtr %r2,%r2 # int * jg compat_sys_time # branch to system call - .globl sys32_mknod_wrapper + .globl sys32_mknod_wrapper sys32_mknod_wrapper: llgtr %r2,%r2 # const char * - lgfr %r3,%r3 # int + lgfr %r3,%r3 # int llgfr %r4,%r4 # dev jg sys_mknod # branch to system call - .globl sys32_chmod_wrapper + .globl sys32_chmod_wrapper sys32_chmod_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # mode_t jg sys_chmod # branch to system call - .globl sys32_lchown16_wrapper + .globl sys32_lchown16_wrapper sys32_lchown16_wrapper: llgtr %r2,%r2 # const char * - llgfr %r3,%r3 # __kernel_old_uid_emu31_t - llgfr %r4,%r4 # __kernel_old_uid_emu31_t + llgfr %r3,%r3 # __kernel_old_uid_emu31_t + llgfr %r4,%r4 # __kernel_old_uid_emu31_t jg sys32_lchown16 # branch to system call - .globl sys32_lseek_wrapper + .globl sys32_lseek_wrapper sys32_lseek_wrapper: llgfr %r2,%r2 # unsigned int lgfr %r3,%r3 # off_t llgfr %r4,%r4 # unsigned int jg sys_lseek # branch to system call -#sys32_getpid_wrapper # void +#sys32_getpid_wrapper # void - .globl sys32_mount_wrapper + .globl sys32_mount_wrapper sys32_mount_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # char * @@ -103,19 +103,19 @@ sys32_mount_wrapper: llgtr %r6,%r6 # void * jg compat_sys_mount # branch to system call - .globl sys32_oldumount_wrapper + .globl sys32_oldumount_wrapper sys32_oldumount_wrapper: llgtr %r2,%r2 # char * jg sys_oldumount # branch to system call - .globl sys32_setuid16_wrapper + .globl sys32_setuid16_wrapper sys32_setuid16_wrapper: - llgfr %r2,%r2 # __kernel_old_uid_emu31_t + llgfr %r2,%r2 # __kernel_old_uid_emu31_t jg sys32_setuid16 # branch to system call -#sys32_getuid16_wrapper # void +#sys32_getuid16_wrapper # void - .globl sys32_ptrace_wrapper + .globl sys32_ptrace_wrapper sys32_ptrace_wrapper: lgfr %r2,%r2 # long lgfr %r3,%r3 # long @@ -123,168 +123,168 @@ sys32_ptrace_wrapper: llgfr %r5,%r5 # long jg sys_ptrace # branch to system call - .globl sys32_alarm_wrapper + .globl sys32_alarm_wrapper sys32_alarm_wrapper: llgfr %r2,%r2 # unsigned int jg sys_alarm # branch to system call -#sys32_pause_wrapper # void +#sys32_pause_wrapper # void - .globl compat_sys_utime_wrapper + .globl compat_sys_utime_wrapper compat_sys_utime_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # struct compat_utimbuf * jg compat_sys_utime # branch to system call - .globl sys32_access_wrapper + .globl sys32_access_wrapper sys32_access_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int jg sys_access # branch to system call - .globl sys32_nice_wrapper + .globl sys32_nice_wrapper sys32_nice_wrapper: lgfr %r2,%r2 # int jg sys_nice # branch to system call -#sys32_sync_wrapper # void +#sys32_sync_wrapper # void - .globl sys32_kill_wrapper + .globl sys32_kill_wrapper sys32_kill_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int jg sys_kill # branch to system call - .globl sys32_rename_wrapper + .globl sys32_rename_wrapper sys32_rename_wrapper: llgtr %r2,%r2 # const char * llgtr %r3,%r3 # const char * jg sys_rename # branch to system call - .globl sys32_mkdir_wrapper + .globl sys32_mkdir_wrapper sys32_mkdir_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int jg sys_mkdir # branch to system call - .globl sys32_rmdir_wrapper + .globl sys32_rmdir_wrapper sys32_rmdir_wrapper: llgtr %r2,%r2 # const char * jg sys_rmdir # branch to system call - .globl sys32_dup_wrapper + .globl sys32_dup_wrapper sys32_dup_wrapper: llgfr %r2,%r2 # unsigned int jg sys_dup # branch to system call - .globl sys32_pipe_wrapper + .globl sys32_pipe_wrapper sys32_pipe_wrapper: llgtr %r2,%r2 # u32 * jg sys_pipe # branch to system call - .globl compat_sys_times_wrapper + .globl compat_sys_times_wrapper compat_sys_times_wrapper: llgtr %r2,%r2 # struct compat_tms * jg compat_sys_times # branch to system call - .globl sys32_brk_wrapper + .globl sys32_brk_wrapper sys32_brk_wrapper: llgtr %r2,%r2 # unsigned long jg sys_brk # branch to system call - .globl sys32_setgid16_wrapper + .globl sys32_setgid16_wrapper sys32_setgid16_wrapper: - llgfr %r2,%r2 # __kernel_old_gid_emu31_t + llgfr %r2,%r2 # __kernel_old_gid_emu31_t jg sys32_setgid16 # branch to system call -#sys32_getgid16_wrapper # void +#sys32_getgid16_wrapper # void .globl sys32_signal_wrapper sys32_signal_wrapper: - lgfr %r2,%r2 # int + lgfr %r2,%r2 # int llgtr %r3,%r3 # __sighandler_t jg sys_signal -#sys32_geteuid16_wrapper # void +#sys32_geteuid16_wrapper # void -#sys32_getegid16_wrapper # void +#sys32_getegid16_wrapper # void - .globl sys32_acct_wrapper + .globl sys32_acct_wrapper sys32_acct_wrapper: llgtr %r2,%r2 # char * jg sys_acct # branch to system call - .globl sys32_umount_wrapper + .globl sys32_umount_wrapper sys32_umount_wrapper: llgtr %r2,%r2 # char * lgfr %r3,%r3 # int jg sys_umount # branch to system call - .globl compat_sys_ioctl_wrapper + .globl compat_sys_ioctl_wrapper compat_sys_ioctl_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned int llgfr %r4,%r4 # unsigned int jg compat_sys_ioctl # branch to system call - .globl compat_sys_fcntl_wrapper + .globl compat_sys_fcntl_wrapper compat_sys_fcntl_wrapper: llgfr %r2,%r2 # unsigned int - llgfr %r3,%r3 # unsigned int + llgfr %r3,%r3 # unsigned int llgfr %r4,%r4 # unsigned long jg compat_sys_fcntl # branch to system call - .globl sys32_setpgid_wrapper + .globl sys32_setpgid_wrapper sys32_setpgid_wrapper: lgfr %r2,%r2 # pid_t lgfr %r3,%r3 # pid_t jg sys_setpgid # branch to system call - .globl sys32_umask_wrapper + .globl sys32_umask_wrapper sys32_umask_wrapper: lgfr %r2,%r2 # int jg sys_umask # branch to system call - .globl sys32_chroot_wrapper + .globl sys32_chroot_wrapper sys32_chroot_wrapper: llgtr %r2,%r2 # char * jg sys_chroot # branch to system call .globl sys32_ustat_wrapper sys32_ustat_wrapper: - llgfr %r2,%r2 # dev_t + llgfr %r2,%r2 # dev_t llgtr %r3,%r3 # struct ustat * jg sys_ustat - .globl sys32_dup2_wrapper + .globl sys32_dup2_wrapper sys32_dup2_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned int jg sys_dup2 # branch to system call -#sys32_getppid_wrapper # void +#sys32_getppid_wrapper # void -#sys32_getpgrp_wrapper # void +#sys32_getpgrp_wrapper # void -#sys32_setsid_wrapper # void +#sys32_setsid_wrapper # void - .globl sys32_sigaction_wrapper + .globl sys32_sigaction_wrapper sys32_sigaction_wrapper: - lgfr %r2,%r2 # int + lgfr %r2,%r2 # int llgtr %r3,%r3 # const struct old_sigaction * llgtr %r4,%r4 # struct old_sigaction32 * jg sys32_sigaction # branch to system call - .globl sys32_setreuid16_wrapper + .globl sys32_setreuid16_wrapper sys32_setreuid16_wrapper: - llgfr %r2,%r2 # __kernel_old_uid_emu31_t - llgfr %r3,%r3 # __kernel_old_uid_emu31_t + llgfr %r2,%r2 # __kernel_old_uid_emu31_t + llgfr %r3,%r3 # __kernel_old_uid_emu31_t jg sys32_setreuid16 # branch to system call - .globl sys32_setregid16_wrapper + .globl sys32_setregid16_wrapper sys32_setregid16_wrapper: - llgfr %r2,%r2 # __kernel_old_gid_emu31_t - llgfr %r3,%r3 # __kernel_old_gid_emu31_t + llgfr %r2,%r2 # __kernel_old_gid_emu31_t + llgfr %r3,%r3 # __kernel_old_gid_emu31_t jg sys32_setregid16 # branch to system call .globl sys_sigsuspend_wrapper @@ -294,95 +294,95 @@ sys_sigsuspend_wrapper: llgfr %r4,%r4 # old_sigset_t jg sys_sigsuspend - .globl compat_sys_sigpending_wrapper + .globl compat_sys_sigpending_wrapper compat_sys_sigpending_wrapper: llgtr %r2,%r2 # compat_old_sigset_t * jg compat_sys_sigpending # branch to system call - .globl sys32_sethostname_wrapper + .globl sys32_sethostname_wrapper sys32_sethostname_wrapper: llgtr %r2,%r2 # char * lgfr %r3,%r3 # int jg sys_sethostname # branch to system call - .globl compat_sys_setrlimit_wrapper + .globl compat_sys_setrlimit_wrapper compat_sys_setrlimit_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # struct rlimit_emu31 * jg compat_sys_setrlimit # branch to system call - .globl compat_sys_old_getrlimit_wrapper + .globl compat_sys_old_getrlimit_wrapper compat_sys_old_getrlimit_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # struct rlimit_emu31 * jg compat_sys_old_getrlimit # branch to system call - .globl compat_sys_getrlimit_wrapper + .globl compat_sys_getrlimit_wrapper compat_sys_getrlimit_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # struct rlimit_emu31 * jg compat_sys_getrlimit # branch to system call - .globl sys32_mmap2_wrapper + .globl sys32_mmap2_wrapper sys32_mmap2_wrapper: llgtr %r2,%r2 # struct mmap_arg_struct_emu31 * jg sys32_mmap2 # branch to system call - .globl compat_sys_getrusage_wrapper + .globl compat_sys_getrusage_wrapper compat_sys_getrusage_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # struct rusage_emu31 * jg compat_sys_getrusage # branch to system call - .globl sys32_gettimeofday_wrapper + .globl sys32_gettimeofday_wrapper sys32_gettimeofday_wrapper: llgtr %r2,%r2 # struct timeval_emu31 * llgtr %r3,%r3 # struct timezone * jg sys32_gettimeofday # branch to system call - .globl sys32_settimeofday_wrapper + .globl sys32_settimeofday_wrapper sys32_settimeofday_wrapper: llgtr %r2,%r2 # struct timeval_emu31 * llgtr %r3,%r3 # struct timezone * jg sys32_settimeofday # branch to system call - .globl sys32_getgroups16_wrapper + .globl sys32_getgroups16_wrapper sys32_getgroups16_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # __kernel_old_gid_emu31_t * jg sys32_getgroups16 # branch to system call - .globl sys32_setgroups16_wrapper + .globl sys32_setgroups16_wrapper sys32_setgroups16_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # __kernel_old_gid_emu31_t * jg sys32_setgroups16 # branch to system call - .globl sys32_symlink_wrapper + .globl sys32_symlink_wrapper sys32_symlink_wrapper: llgtr %r2,%r2 # const char * llgtr %r3,%r3 # const char * jg sys_symlink # branch to system call - .globl sys32_readlink_wrapper + .globl sys32_readlink_wrapper sys32_readlink_wrapper: llgtr %r2,%r2 # const char * llgtr %r3,%r3 # char * lgfr %r4,%r4 # int jg sys_readlink # branch to system call - .globl sys32_uselib_wrapper + .globl sys32_uselib_wrapper sys32_uselib_wrapper: llgtr %r2,%r2 # const char * jg sys_uselib # branch to system call - .globl sys32_swapon_wrapper + .globl sys32_swapon_wrapper sys32_swapon_wrapper: llgtr %r2,%r2 # const char * lgfr %r3,%r3 # int jg sys_swapon # branch to system call - .globl sys32_reboot_wrapper + .globl sys32_reboot_wrapper sys32_reboot_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int @@ -390,121 +390,121 @@ sys32_reboot_wrapper: llgtr %r5,%r5 # void * jg sys_reboot # branch to system call - .globl old32_readdir_wrapper + .globl old32_readdir_wrapper old32_readdir_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # void * llgfr %r4,%r4 # unsigned int jg compat_sys_old_readdir # branch to system call - .globl old32_mmap_wrapper + .globl old32_mmap_wrapper old32_mmap_wrapper: llgtr %r2,%r2 # struct mmap_arg_struct_emu31 * jg old32_mmap # branch to system call - .globl sys32_munmap_wrapper + .globl sys32_munmap_wrapper sys32_munmap_wrapper: llgfr %r2,%r2 # unsigned long - llgfr %r3,%r3 # size_t + llgfr %r3,%r3 # size_t jg sys_munmap # branch to system call - .globl sys32_truncate_wrapper + .globl sys32_truncate_wrapper sys32_truncate_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # unsigned long jg sys_truncate # branch to system call - .globl sys32_ftruncate_wrapper + .globl sys32_ftruncate_wrapper sys32_ftruncate_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned long jg sys_ftruncate # branch to system call - .globl sys32_fchmod_wrapper + .globl sys32_fchmod_wrapper sys32_fchmod_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # mode_t jg sys_fchmod # branch to system call - .globl sys32_fchown16_wrapper + .globl sys32_fchown16_wrapper sys32_fchown16_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # compat_uid_t llgfr %r4,%r4 # compat_uid_t jg sys32_fchown16 # branch to system call - .globl sys32_getpriority_wrapper + .globl sys32_getpriority_wrapper sys32_getpriority_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int jg sys_getpriority # branch to system call - .globl sys32_setpriority_wrapper + .globl sys32_setpriority_wrapper sys32_setpriority_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int lgfr %r4,%r4 # int jg sys_setpriority # branch to system call - .globl compat_sys_statfs_wrapper + .globl compat_sys_statfs_wrapper compat_sys_statfs_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # struct compat_statfs * jg compat_sys_statfs # branch to system call - .globl compat_sys_fstatfs_wrapper + .globl compat_sys_fstatfs_wrapper compat_sys_fstatfs_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # struct compat_statfs * jg compat_sys_fstatfs # branch to system call - .globl compat_sys_socketcall_wrapper + .globl compat_sys_socketcall_wrapper compat_sys_socketcall_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # u32 * jg compat_sys_socketcall # branch to system call - .globl sys32_syslog_wrapper + .globl sys32_syslog_wrapper sys32_syslog_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # char * lgfr %r4,%r4 # int jg sys_syslog # branch to system call - .globl compat_sys_setitimer_wrapper + .globl compat_sys_setitimer_wrapper compat_sys_setitimer_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # struct itimerval_emu31 * llgtr %r4,%r4 # struct itimerval_emu31 * jg compat_sys_setitimer # branch to system call - .globl compat_sys_getitimer_wrapper + .globl compat_sys_getitimer_wrapper compat_sys_getitimer_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # struct itimerval_emu31 * jg compat_sys_getitimer # branch to system call - .globl compat_sys_newstat_wrapper + .globl compat_sys_newstat_wrapper compat_sys_newstat_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # struct stat_emu31 * jg compat_sys_newstat # branch to system call - .globl compat_sys_newlstat_wrapper + .globl compat_sys_newlstat_wrapper compat_sys_newlstat_wrapper: llgtr %r2,%r2 # char * llgtr %r3,%r3 # struct stat_emu31 * jg compat_sys_newlstat # branch to system call - .globl compat_sys_newfstat_wrapper + .globl compat_sys_newfstat_wrapper compat_sys_newfstat_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # struct stat_emu31 * jg compat_sys_newfstat # branch to system call -#sys32_vhangup_wrapper # void +#sys32_vhangup_wrapper # void - .globl compat_sys_wait4_wrapper + .globl compat_sys_wait4_wrapper compat_sys_wait4_wrapper: lgfr %r2,%r2 # pid_t llgtr %r3,%r3 # unsigned int * @@ -512,17 +512,17 @@ compat_sys_wait4_wrapper: llgtr %r5,%r5 # struct rusage * jg compat_sys_wait4 # branch to system call - .globl sys32_swapoff_wrapper + .globl sys32_swapoff_wrapper sys32_swapoff_wrapper: llgtr %r2,%r2 # const char * jg sys_swapoff # branch to system call - .globl sys32_sysinfo_wrapper + .globl sys32_sysinfo_wrapper sys32_sysinfo_wrapper: llgtr %r2,%r2 # struct sysinfo_emu31 * jg sys32_sysinfo # branch to system call - .globl sys32_ipc_wrapper + .globl sys32_ipc_wrapper sys32_ipc_wrapper: llgfr %r2,%r2 # uint lgfr %r3,%r3 # int @@ -531,59 +531,59 @@ sys32_ipc_wrapper: llgfr %r6,%r6 # u32 jg sys32_ipc # branch to system call - .globl sys32_fsync_wrapper + .globl sys32_fsync_wrapper sys32_fsync_wrapper: llgfr %r2,%r2 # unsigned int jg sys_fsync # branch to system call -#sys32_sigreturn_wrapper # done in sigreturn_glue +#sys32_sigreturn_wrapper # done in sigreturn_glue -#sys32_clone_wrapper # done in clone_glue +#sys32_clone_wrapper # done in clone_glue - .globl sys32_setdomainname_wrapper + .globl sys32_setdomainname_wrapper sys32_setdomainname_wrapper: llgtr %r2,%r2 # char * lgfr %r3,%r3 # int jg sys_setdomainname # branch to system call - .globl sys32_newuname_wrapper + .globl sys32_newuname_wrapper sys32_newuname_wrapper: llgtr %r2,%r2 # struct new_utsname * jg s390x_newuname # branch to system call - .globl compat_sys_adjtimex_wrapper + .globl compat_sys_adjtimex_wrapper compat_sys_adjtimex_wrapper: llgtr %r2,%r2 # struct compat_timex * jg compat_sys_adjtimex # branch to system call - .globl sys32_mprotect_wrapper + .globl sys32_mprotect_wrapper sys32_mprotect_wrapper: llgtr %r2,%r2 # unsigned long (actually pointer llgfr %r3,%r3 # size_t llgfr %r4,%r4 # unsigned long jg sys_mprotect # branch to system call - .globl compat_sys_sigprocmask_wrapper + .globl compat_sys_sigprocmask_wrapper compat_sys_sigprocmask_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # compat_old_sigset_t * llgtr %r4,%r4 # compat_old_sigset_t * jg compat_sys_sigprocmask # branch to system call - .globl sys32_init_module_wrapper + .globl sys32_init_module_wrapper sys32_init_module_wrapper: llgtr %r2,%r2 # void * llgfr %r3,%r3 # unsigned long llgtr %r4,%r4 # char * jg sys32_init_module # branch to system call - .globl sys32_delete_module_wrapper + .globl sys32_delete_module_wrapper sys32_delete_module_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # unsigned int jg sys32_delete_module # branch to system call - .globl sys32_quotactl_wrapper + .globl sys32_quotactl_wrapper sys32_quotactl_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # const char * @@ -591,45 +591,45 @@ sys32_quotactl_wrapper: llgtr %r5,%r5 # caddr_t jg sys_quotactl # branch to system call - .globl sys32_getpgid_wrapper + .globl sys32_getpgid_wrapper sys32_getpgid_wrapper: lgfr %r2,%r2 # pid_t jg sys_getpgid # branch to system call - .globl sys32_fchdir_wrapper + .globl sys32_fchdir_wrapper sys32_fchdir_wrapper: llgfr %r2,%r2 # unsigned int jg sys_fchdir # branch to system call - .globl sys32_bdflush_wrapper + .globl sys32_bdflush_wrapper sys32_bdflush_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # long jg sys_bdflush # branch to system call - .globl sys32_sysfs_wrapper + .globl sys32_sysfs_wrapper sys32_sysfs_wrapper: lgfr %r2,%r2 # int llgfr %r3,%r3 # unsigned long llgfr %r4,%r4 # unsigned long jg sys_sysfs # branch to system call - .globl sys32_personality_wrapper + .globl sys32_personality_wrapper sys32_personality_wrapper: llgfr %r2,%r2 # unsigned long jg s390x_personality # branch to system call - .globl sys32_setfsuid16_wrapper + .globl sys32_setfsuid16_wrapper sys32_setfsuid16_wrapper: - llgfr %r2,%r2 # __kernel_old_uid_emu31_t + llgfr %r2,%r2 # __kernel_old_uid_emu31_t jg sys32_setfsuid16 # branch to system call - .globl sys32_setfsgid16_wrapper + .globl sys32_setfsgid16_wrapper sys32_setfsgid16_wrapper: - llgfr %r2,%r2 # __kernel_old_gid_emu31_t + llgfr %r2,%r2 # __kernel_old_gid_emu31_t jg sys32_setfsgid16 # branch to system call - .globl sys32_llseek_wrapper + .globl sys32_llseek_wrapper sys32_llseek_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned long @@ -638,14 +638,14 @@ sys32_llseek_wrapper: llgfr %r6,%r6 # unsigned int jg sys_llseek # branch to system call - .globl sys32_getdents_wrapper + .globl sys32_getdents_wrapper sys32_getdents_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # void * llgfr %r4,%r4 # unsigned int jg compat_sys_getdents # branch to system call - .globl compat_sys_select_wrapper + .globl compat_sys_select_wrapper compat_sys_select_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # compat_fd_set * @@ -654,113 +654,113 @@ compat_sys_select_wrapper: llgtr %r6,%r6 # struct compat_timeval * jg compat_sys_select # branch to system call - .globl sys32_flock_wrapper + .globl sys32_flock_wrapper sys32_flock_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned int jg sys_flock # branch to system call - .globl sys32_msync_wrapper + .globl sys32_msync_wrapper sys32_msync_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # size_t lgfr %r4,%r4 # int jg sys_msync # branch to system call - .globl compat_sys_readv_wrapper + .globl compat_sys_readv_wrapper compat_sys_readv_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const struct compat_iovec * llgfr %r4,%r4 # unsigned long jg compat_sys_readv # branch to system call - .globl compat_sys_writev_wrapper + .globl compat_sys_writev_wrapper compat_sys_writev_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const struct compat_iovec * llgfr %r4,%r4 # unsigned long jg compat_sys_writev # branch to system call - .globl sys32_getsid_wrapper + .globl sys32_getsid_wrapper sys32_getsid_wrapper: lgfr %r2,%r2 # pid_t jg sys_getsid # branch to system call - .globl sys32_fdatasync_wrapper + .globl sys32_fdatasync_wrapper sys32_fdatasync_wrapper: llgfr %r2,%r2 # unsigned int jg sys_fdatasync # branch to system call -#sys32_sysctl_wrapper # tbd +#sys32_sysctl_wrapper # tbd - .globl sys32_mlock_wrapper + .globl sys32_mlock_wrapper sys32_mlock_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # size_t jg sys_mlock # branch to system call - .globl sys32_munlock_wrapper + .globl sys32_munlock_wrapper sys32_munlock_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # size_t jg sys_munlock # branch to system call - .globl sys32_mlockall_wrapper + .globl sys32_mlockall_wrapper sys32_mlockall_wrapper: lgfr %r2,%r2 # int jg sys_mlockall # branch to system call -#sys32_munlockall_wrapper # void +#sys32_munlockall_wrapper # void - .globl sys32_sched_setparam_wrapper + .globl sys32_sched_setparam_wrapper sys32_sched_setparam_wrapper: lgfr %r2,%r2 # pid_t llgtr %r3,%r3 # struct sched_param * jg sys_sched_setparam # branch to system call - .globl sys32_sched_getparam_wrapper + .globl sys32_sched_getparam_wrapper sys32_sched_getparam_wrapper: lgfr %r2,%r2 # pid_t llgtr %r3,%r3 # struct sched_param * jg sys_sched_getparam # branch to system call - .globl sys32_sched_setscheduler_wrapper + .globl sys32_sched_setscheduler_wrapper sys32_sched_setscheduler_wrapper: lgfr %r2,%r2 # pid_t lgfr %r3,%r3 # int llgtr %r4,%r4 # struct sched_param * jg sys_sched_setscheduler # branch to system call - .globl sys32_sched_getscheduler_wrapper + .globl sys32_sched_getscheduler_wrapper sys32_sched_getscheduler_wrapper: lgfr %r2,%r2 # pid_t jg sys_sched_getscheduler # branch to system call -#sys32_sched_yield_wrapper # void +#sys32_sched_yield_wrapper # void - .globl sys32_sched_get_priority_max_wrapper + .globl sys32_sched_get_priority_max_wrapper sys32_sched_get_priority_max_wrapper: lgfr %r2,%r2 # int jg sys_sched_get_priority_max # branch to system call - .globl sys32_sched_get_priority_min_wrapper + .globl sys32_sched_get_priority_min_wrapper sys32_sched_get_priority_min_wrapper: lgfr %r2,%r2 # int jg sys_sched_get_priority_min # branch to system call - .globl sys32_sched_rr_get_interval_wrapper + .globl sys32_sched_rr_get_interval_wrapper sys32_sched_rr_get_interval_wrapper: lgfr %r2,%r2 # pid_t llgtr %r3,%r3 # struct compat_timespec * jg sys32_sched_rr_get_interval # branch to system call - .globl compat_sys_nanosleep_wrapper + .globl compat_sys_nanosleep_wrapper compat_sys_nanosleep_wrapper: llgtr %r2,%r2 # struct compat_timespec * llgtr %r3,%r3 # struct compat_timespec * jg compat_sys_nanosleep # branch to system call - .globl sys32_mremap_wrapper + .globl sys32_mremap_wrapper sys32_mremap_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # unsigned long @@ -769,49 +769,49 @@ sys32_mremap_wrapper: llgfr %r6,%r6 # unsigned long jg sys_mremap # branch to system call - .globl sys32_setresuid16_wrapper + .globl sys32_setresuid16_wrapper sys32_setresuid16_wrapper: - llgfr %r2,%r2 # __kernel_old_uid_emu31_t - llgfr %r3,%r3 # __kernel_old_uid_emu31_t - llgfr %r4,%r4 # __kernel_old_uid_emu31_t + llgfr %r2,%r2 # __kernel_old_uid_emu31_t + llgfr %r3,%r3 # __kernel_old_uid_emu31_t + llgfr %r4,%r4 # __kernel_old_uid_emu31_t jg sys32_setresuid16 # branch to system call - .globl sys32_getresuid16_wrapper + .globl sys32_getresuid16_wrapper sys32_getresuid16_wrapper: llgtr %r2,%r2 # __kernel_old_uid_emu31_t * llgtr %r3,%r3 # __kernel_old_uid_emu31_t * llgtr %r4,%r4 # __kernel_old_uid_emu31_t * jg sys32_getresuid16 # branch to system call - .globl sys32_poll_wrapper + .globl sys32_poll_wrapper sys32_poll_wrapper: - llgtr %r2,%r2 # struct pollfd * - llgfr %r3,%r3 # unsigned int - lgfr %r4,%r4 # long + llgtr %r2,%r2 # struct pollfd * + llgfr %r3,%r3 # unsigned int + lgfr %r4,%r4 # long jg sys_poll # branch to system call - .globl compat_sys_nfsservctl_wrapper + .globl compat_sys_nfsservctl_wrapper compat_sys_nfsservctl_wrapper: - lgfr %r2,%r2 # int + lgfr %r2,%r2 # int llgtr %r3,%r3 # struct compat_nfsctl_arg* llgtr %r4,%r4 # union compat_nfsctl_res* jg compat_sys_nfsservctl # branch to system call - .globl sys32_setresgid16_wrapper + .globl sys32_setresgid16_wrapper sys32_setresgid16_wrapper: - llgfr %r2,%r2 # __kernel_old_gid_emu31_t - llgfr %r3,%r3 # __kernel_old_gid_emu31_t - llgfr %r4,%r4 # __kernel_old_gid_emu31_t + llgfr %r2,%r2 # __kernel_old_gid_emu31_t + llgfr %r3,%r3 # __kernel_old_gid_emu31_t + llgfr %r4,%r4 # __kernel_old_gid_emu31_t jg sys32_setresgid16 # branch to system call - .globl sys32_getresgid16_wrapper + .globl sys32_getresgid16_wrapper sys32_getresgid16_wrapper: llgtr %r2,%r2 # __kernel_old_gid_emu31_t * llgtr %r3,%r3 # __kernel_old_gid_emu31_t * llgtr %r4,%r4 # __kernel_old_gid_emu31_t * jg sys32_getresgid16 # branch to system call - .globl sys32_prctl_wrapper + .globl sys32_prctl_wrapper sys32_prctl_wrapper: lgfr %r2,%r2 # int llgfr %r3,%r3 # unsigned long @@ -820,9 +820,9 @@ sys32_prctl_wrapper: llgfr %r6,%r6 # unsigned long jg sys_prctl # branch to system call -#sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue +#sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue - .globl sys32_rt_sigaction_wrapper + .globl sys32_rt_sigaction_wrapper sys32_rt_sigaction_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # const struct sigaction_emu31 * @@ -830,7 +830,7 @@ sys32_rt_sigaction_wrapper: llgfr %r5,%r5 # size_t jg sys32_rt_sigaction # branch to system call - .globl sys32_rt_sigprocmask_wrapper + .globl sys32_rt_sigprocmask_wrapper sys32_rt_sigprocmask_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # old_sigset_emu31 * @@ -838,13 +838,13 @@ sys32_rt_sigprocmask_wrapper: llgfr %r5,%r5 # size_t jg sys32_rt_sigprocmask # branch to system call - .globl sys32_rt_sigpending_wrapper + .globl sys32_rt_sigpending_wrapper sys32_rt_sigpending_wrapper: llgtr %r2,%r2 # sigset_emu31 * llgfr %r3,%r3 # size_t jg sys32_rt_sigpending # branch to system call - .globl compat_sys_rt_sigtimedwait_wrapper + .globl compat_sys_rt_sigtimedwait_wrapper compat_sys_rt_sigtimedwait_wrapper: llgtr %r2,%r2 # const sigset_emu31_t * llgtr %r3,%r3 # siginfo_emu31_t * @@ -852,7 +852,7 @@ compat_sys_rt_sigtimedwait_wrapper: llgfr %r5,%r5 # size_t jg compat_sys_rt_sigtimedwait # branch to system call - .globl sys32_rt_sigqueueinfo_wrapper + .globl sys32_rt_sigqueueinfo_wrapper sys32_rt_sigqueueinfo_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int @@ -865,7 +865,7 @@ compat_sys_rt_sigsuspend_wrapper: llgfr %r3,%r3 # compat_size_t jg compat_sys_rt_sigsuspend - .globl sys32_pread64_wrapper + .globl sys32_pread64_wrapper sys32_pread64_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # char * @@ -874,7 +874,7 @@ sys32_pread64_wrapper: llgfr %r6,%r6 # u32 jg sys32_pread64 # branch to system call - .globl sys32_pwrite64_wrapper + .globl sys32_pwrite64_wrapper sys32_pwrite64_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # const char * @@ -883,26 +883,26 @@ sys32_pwrite64_wrapper: llgfr %r6,%r6 # u32 jg sys32_pwrite64 # branch to system call - .globl sys32_chown16_wrapper + .globl sys32_chown16_wrapper sys32_chown16_wrapper: llgtr %r2,%r2 # const char * - llgfr %r3,%r3 # __kernel_old_uid_emu31_t - llgfr %r4,%r4 # __kernel_old_gid_emu31_t + llgfr %r3,%r3 # __kernel_old_uid_emu31_t + llgfr %r4,%r4 # __kernel_old_gid_emu31_t jg sys32_chown16 # branch to system call - .globl sys32_getcwd_wrapper + .globl sys32_getcwd_wrapper sys32_getcwd_wrapper: llgtr %r2,%r2 # char * llgfr %r3,%r3 # unsigned long jg sys_getcwd # branch to system call - .globl sys32_capget_wrapper + .globl sys32_capget_wrapper sys32_capget_wrapper: llgtr %r2,%r2 # cap_user_header_t llgtr %r3,%r3 # cap_user_data_t jg sys_capget # branch to system call - .globl sys32_capset_wrapper + .globl sys32_capset_wrapper sys32_capset_wrapper: llgtr %r2,%r2 # cap_user_header_t llgtr %r3,%r3 # const cap_user_data_t @@ -910,11 +910,11 @@ sys32_capset_wrapper: .globl sys32_sigaltstack_wrapper sys32_sigaltstack_wrapper: - llgtr %r2,%r2 # const stack_emu31_t * - llgtr %r3,%r3 # stack_emu31_t * + llgtr %r2,%r2 # const stack_emu31_t * + llgtr %r3,%r3 # stack_emu31_t * jg sys32_sigaltstack - .globl sys32_sendfile_wrapper + .globl sys32_sendfile_wrapper sys32_sendfile_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int @@ -922,33 +922,33 @@ sys32_sendfile_wrapper: llgfr %r5,%r5 # size_t jg sys32_sendfile # branch to system call -#sys32_vfork_wrapper # done in vfork_glue +#sys32_vfork_wrapper # done in vfork_glue - .globl sys32_truncate64_wrapper + .globl sys32_truncate64_wrapper sys32_truncate64_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # unsigned long llgfr %r4,%r4 # unsigned long jg sys32_truncate64 # branch to system call - .globl sys32_ftruncate64_wrapper + .globl sys32_ftruncate64_wrapper sys32_ftruncate64_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # unsigned long llgfr %r4,%r4 # unsigned long jg sys32_ftruncate64 # branch to system call - .globl sys32_lchown_wrapper + .globl sys32_lchown_wrapper sys32_lchown_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # uid_t llgfr %r4,%r4 # gid_t jg sys_lchown # branch to system call -#sys32_getuid_wrapper # void -#sys32_getgid_wrapper # void -#sys32_geteuid_wrapper # void -#sys32_getegid_wrapper # void +#sys32_getuid_wrapper # void +#sys32_getgid_wrapper # void +#sys32_geteuid_wrapper # void +#sys32_getegid_wrapper # void .globl sys32_setreuid_wrapper sys32_setreuid_wrapper: @@ -962,111 +962,111 @@ sys32_setregid_wrapper: llgfr %r3,%r3 # gid_t jg sys_setregid # branch to system call - .globl sys32_getgroups_wrapper + .globl sys32_getgroups_wrapper sys32_getgroups_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # gid_t * jg sys_getgroups # branch to system call - .globl sys32_setgroups_wrapper + .globl sys32_setgroups_wrapper sys32_setgroups_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # gid_t * jg sys_setgroups # branch to system call - .globl sys32_fchown_wrapper + .globl sys32_fchown_wrapper sys32_fchown_wrapper: llgfr %r2,%r2 # unsigned int llgfr %r3,%r3 # uid_t llgfr %r4,%r4 # gid_t jg sys_fchown # branch to system call - .globl sys32_setresuid_wrapper + .globl sys32_setresuid_wrapper sys32_setresuid_wrapper: llgfr %r2,%r2 # uid_t llgfr %r3,%r3 # uid_t llgfr %r4,%r4 # uid_t jg sys_setresuid # branch to system call - .globl sys32_getresuid_wrapper + .globl sys32_getresuid_wrapper sys32_getresuid_wrapper: llgtr %r2,%r2 # uid_t * llgtr %r3,%r3 # uid_t * llgtr %r4,%r4 # uid_t * jg sys_getresuid # branch to system call - .globl sys32_setresgid_wrapper + .globl sys32_setresgid_wrapper sys32_setresgid_wrapper: llgfr %r2,%r2 # gid_t llgfr %r3,%r3 # gid_t llgfr %r4,%r4 # gid_t jg sys_setresgid # branch to system call - .globl sys32_getresgid_wrapper + .globl sys32_getresgid_wrapper sys32_getresgid_wrapper: llgtr %r2,%r2 # gid_t * llgtr %r3,%r3 # gid_t * llgtr %r4,%r4 # gid_t * jg sys_getresgid # branch to system call - .globl sys32_chown_wrapper + .globl sys32_chown_wrapper sys32_chown_wrapper: llgtr %r2,%r2 # const char * llgfr %r3,%r3 # uid_t llgfr %r4,%r4 # gid_t jg sys_chown # branch to system call - .globl sys32_setuid_wrapper + .globl sys32_setuid_wrapper sys32_setuid_wrapper: llgfr %r2,%r2 # uid_t jg sys_setuid # branch to system call - .globl sys32_setgid_wrapper + .globl sys32_setgid_wrapper sys32_setgid_wrapper: llgfr %r2,%r2 # gid_t jg sys_setgid # branch to system call - .globl sys32_setfsuid_wrapper + .globl sys32_setfsuid_wrapper sys32_setfsuid_wrapper: llgfr %r2,%r2 # uid_t jg sys_setfsuid # branch to system call - .globl sys32_setfsgid_wrapper + .globl sys32_setfsgid_wrapper sys32_setfsgid_wrapper: llgfr %r2,%r2 # gid_t jg sys_setfsgid # branch to system call - .globl sys32_pivot_root_wrapper + .globl sys32_pivot_root_wrapper sys32_pivot_root_wrapper: llgtr %r2,%r2 # const char * llgtr %r3,%r3 # const char * jg sys_pivot_root # branch to system call - .globl sys32_mincore_wrapper + .globl sys32_mincore_wrapper sys32_mincore_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # size_t llgtr %r4,%r4 # unsigned char * jg sys_mincore # branch to system call - .globl sys32_madvise_wrapper + .globl sys32_madvise_wrapper sys32_madvise_wrapper: llgfr %r2,%r2 # unsigned long llgfr %r3,%r3 # size_t lgfr %r4,%r4 # int jg sys_madvise # branch to system call - .globl sys32_getdents64_wrapper + .globl sys32_getdents64_wrapper sys32_getdents64_wrapper: llgfr %r2,%r2 # unsigned int llgtr %r3,%r3 # void * llgfr %r4,%r4 # unsigned int jg sys_getdents64 # branch to system call - .globl compat_sys_fcntl64_wrapper + .globl compat_sys_fcntl64_wrapper compat_sys_fcntl64_wrapper: llgfr %r2,%r2 # unsigned int - llgfr %r3,%r3 # unsigned int + llgfr %r3,%r3 # unsigned int llgfr %r4,%r4 # unsigned long jg compat_sys_fcntl64 # branch to system call @@ -1087,10 +1087,10 @@ sys32_stime_wrapper: llgtr %r2,%r2 # long * jg compat_sys_stime # branch to system call - .globl sys32_sysctl_wrapper + .globl sys32_sysctl_wrapper sys32_sysctl_wrapper: - llgtr %r2,%r2 # struct __sysctl_args32 * - jg sys32_sysctl + llgtr %r2,%r2 # struct __sysctl_args32 * + jg sys32_sysctl .globl sys32_fstat64_wrapper sys32_fstat64_wrapper: @@ -1098,7 +1098,7 @@ sys32_fstat64_wrapper: llgtr %r3,%r3 # struct stat64 * jg sys32_fstat64 # branch to system call - .globl compat_sys_futex_wrapper + .globl compat_sys_futex_wrapper compat_sys_futex_wrapper: llgtr %r2,%r2 # u32 * lgfr %r3,%r3 # int @@ -1213,22 +1213,22 @@ sys32_sched_getaffinity_wrapper: llgtr %r4,%r4 # unsigned long * jg compat_sys_sched_getaffinity - .globl sys32_exit_group_wrapper + .globl sys32_exit_group_wrapper sys32_exit_group_wrapper: lgfr %r2,%r2 # int jg sys_exit_group # branch to system call - .globl sys32_set_tid_address_wrapper + .globl sys32_set_tid_address_wrapper sys32_set_tid_address_wrapper: llgtr %r2,%r2 # int * jg sys_set_tid_address # branch to system call - .globl sys_epoll_create_wrapper + .globl sys_epoll_create_wrapper sys_epoll_create_wrapper: lgfr %r2,%r2 # int jg sys_epoll_create # branch to system call - .globl sys_epoll_ctl_wrapper + .globl sys_epoll_ctl_wrapper sys_epoll_ctl_wrapper: lgfr %r2,%r2 # int lgfr %r3,%r3 # int @@ -1236,7 +1236,7 @@ sys_epoll_ctl_wrapper: llgtr %r5,%r5 # struct epoll_event * jg sys_epoll_ctl # branch to system call - .globl sys_epoll_wait_wrapper + .globl sys_epoll_wait_wrapper sys_epoll_wait_wrapper: lgfr %r2,%r2 # int llgtr %r3,%r3 # struct epoll_event * diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 4ef44e536b2c..1eae74e72f95 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c @@ -25,11 +25,8 @@ static char cpcmd_buf[241]; */ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) { - const int mask = 0x40000000L; - unsigned long flags; - int return_code; - int return_len; - int cmdlen; + unsigned long flags, cmdlen; + int return_code, return_len; spin_lock_irqsave(&cpcmd_lock, flags); cmdlen = strlen(cmd); @@ -38,64 +35,44 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) ASCEBC(cpcmd_buf, cmdlen); if (response != NULL && rlen > 0) { + register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf; + register unsigned long reg3 asm ("3") = (addr_t) response; + register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L; + register unsigned long reg5 asm ("5") = rlen; + memset(response, 0, rlen); + asm volatile( #ifndef CONFIG_64BIT - asm volatile ( "lra 2,0(%2)\n" - "lr 4,%3\n" - "o 4,%6\n" - "lra 3,0(%4)\n" - "lr 5,%5\n" - "diag 2,4,0x8\n" - "brc 8, 1f\n" - "ar 5, %5\n" - "1: \n" - "lr %0,4\n" - "lr %1,5\n" - : "=d" (return_code), "=d" (return_len) - : "a" (cpcmd_buf), "d" (cmdlen), - "a" (response), "d" (rlen), "m" (mask) - : "cc", "2", "3", "4", "5" ); + " diag %2,%0,0x8\n" + " brc 8,1f\n" + " ar %1,%4\n" #else /* CONFIG_64BIT */ - asm volatile ( "lrag 2,0(%2)\n" - "lgr 4,%3\n" - "o 4,%6\n" - "lrag 3,0(%4)\n" - "lgr 5,%5\n" - "sam31\n" - "diag 2,4,0x8\n" - "sam64\n" - "brc 8, 1f\n" - "agr 5, %5\n" - "1: \n" - "lgr %0,4\n" - "lgr %1,5\n" - : "=d" (return_code), "=d" (return_len) - : "a" (cpcmd_buf), "d" (cmdlen), - "a" (response), "d" (rlen), "m" (mask) - : "cc", "2", "3", "4", "5" ); + " sam31\n" + " diag %2,%0,0x8\n" + " sam64\n" + " brc 8,1f\n" + " agr %1,%4\n" #endif /* CONFIG_64BIT */ + "1:\n" + : "+d" (reg4), "+d" (reg5) + : "d" (reg2), "d" (reg3), "d" (rlen) : "cc"); + return_code = (int) reg4; + return_len = (int) reg5; EBCASC(response, rlen); } else { + register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf; + register unsigned long reg3 asm ("3") = cmdlen; return_len = 0; + asm volatile( #ifndef CONFIG_64BIT - asm volatile ( "lra 2,0(%1)\n" - "lr 3,%2\n" - "diag 2,3,0x8\n" - "lr %0,3\n" - : "=d" (return_code) - : "a" (cpcmd_buf), "d" (cmdlen) - : "2", "3" ); + " diag %1,%0,0x8\n" #else /* CONFIG_64BIT */ - asm volatile ( "lrag 2,0(%1)\n" - "lgr 3,%2\n" - "sam31\n" - "diag 2,3,0x8\n" - "sam64\n" - "lgr %0,3\n" - : "=d" (return_code) - : "a" (cpcmd_buf), "d" (cmdlen) - : "2", "3" ); + " sam31\n" + " diag %1,%0,0x8\n" + " sam64\n" #endif /* CONFIG_64BIT */ + : "+d" (reg3) : "d" (reg2) : "cc"); + return_code = (int) reg3; } spin_unlock_irqrestore(&cpcmd_lock, flags); if (response_code != NULL) diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index 7ba20922a535..43f3d0c7e132 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -603,7 +603,7 @@ debug_open(struct inode *inode, struct file *file) debug_info_t *debug_info, *debug_info_snapshot; down(&debug_lock); - debug_info = (struct debug_info*)file->f_dentry->d_inode->u.generic_ip; + debug_info = file->f_dentry->d_inode->i_private; /* find debug view */ for (i = 0; i < DEBUG_MAX_VIEWS; i++) { if (!debug_info->views[i]) diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 5b5799ac8f83..dddc3de30401 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -4,8 +4,8 @@ * * Copyright (C) IBM Corp. 1999,2006 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - * Hartmut Penner (hp@de.ibm.com), - * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), + * Hartmut Penner (hp@de.ibm.com), + * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), * Heiko Carstens <heiko.carstens@de.ibm.com> */ @@ -24,29 +24,29 @@ * Stack layout for the system_call stack entry. * The first few entries are identical to the user_regs_struct. */ -SP_PTREGS = STACK_FRAME_OVERHEAD -SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS -SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW -SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS -SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 4 -SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8 -SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 12 -SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16 -SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 20 -SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24 -SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 28 -SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32 -SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 36 -SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40 -SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 44 -SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48 -SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 52 -SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56 -SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60 -SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 -SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC -SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP -SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE +SP_PTREGS = STACK_FRAME_OVERHEAD +SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS +SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW +SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS +SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 4 +SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8 +SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 12 +SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16 +SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 20 +SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24 +SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 28 +SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32 +SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 36 +SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40 +SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 44 +SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48 +SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 52 +SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56 +SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60 +SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 +SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC +SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP +SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \ _TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP ) @@ -81,14 +81,14 @@ STACK_SIZE = 1 << STACK_SHIFT * R15 - kernel stack pointer */ - .macro STORE_TIMER lc_offset + .macro STORE_TIMER lc_offset #ifdef CONFIG_VIRT_CPU_ACCOUNTING stpt \lc_offset #endif .endm #ifdef CONFIG_VIRT_CPU_ACCOUNTING - .macro UPDATE_VTIME lc_from,lc_to,lc_sum + .macro UPDATE_VTIME lc_from,lc_to,lc_sum lm %r10,%r11,\lc_from sl %r10,\lc_to sl %r11,\lc_to+4 @@ -147,7 +147,7 @@ STACK_SIZE = 1 << STACK_SHIFT 2: .endm - .macro CREATE_STACK_FRAME psworg,savearea + .macro CREATE_STACK_FRAME psworg,savearea s %r15,BASED(.Lc_spsize) # make room for registers & psw mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack la %r12,\psworg @@ -160,7 +160,7 @@ STACK_SIZE = 1 << STACK_SHIFT st %r12,__SF_BACKCHAIN(%r15) # clear back chain .endm - .macro RESTORE_ALL psworg,sync + .macro RESTORE_ALL psworg,sync mvc \psworg(8),SP_PSW(%r15) # move user PSW to lowcore .if !\sync ni \psworg+1,0xfd # clear wait state bit @@ -177,16 +177,16 @@ STACK_SIZE = 1 << STACK_SHIFT * Returns: * gpr2 = prev */ - .globl __switch_to + .globl __switch_to __switch_to: - basr %r1,0 + basr %r1,0 __switch_to_base: tm __THREAD_per(%r3),0xe8 # new process is using per ? bz __switch_to_noper-__switch_to_base(%r1) # if not we're fine - stctl %c9,%c11,__SF_EMPTY(%r15) # We are using per stuff - clc __THREAD_per(12,%r3),__SF_EMPTY(%r15) - be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's - lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't + stctl %c9,%c11,__SF_EMPTY(%r15) # We are using per stuff + clc __THREAD_per(12,%r3),__SF_EMPTY(%r15) + be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's + lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't __switch_to_noper: l %r4,__THREAD_info(%r2) # get thread_info of prev tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending? @@ -195,13 +195,13 @@ __switch_to_noper: l %r4,__THREAD_info(%r3) # get thread_info of next oi __TI_flags+3(%r4),_TIF_MCCK_PENDING # set it in next __switch_to_no_mcck: - stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task + stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp lm %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task st %r3,__LC_CURRENT # __LC_CURRENT = current task struct lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 - l %r3,__THREAD_info(%r3) # load thread_info from task struct + l %r3,__THREAD_info(%r3) # load thread_info from task struct st %r3,__LC_THREAD_INFO ahi %r3,STACK_SIZE st %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack @@ -213,7 +213,7 @@ __critical_start: * are executed with interrupts enabled. */ - .globl system_call + .globl system_call system_call: STORE_TIMER __LC_SYNC_ENTER_TIMER sysc_saveall: @@ -233,24 +233,24 @@ sysc_update: #endif sysc_do_svc: l %r9,__LC_THREAD_INFO # load pointer to thread_info struct - sla %r7,2 # *4 and test for svc 0 - bnz BASED(sysc_nr_ok) # svc number > 0 + sla %r7,2 # *4 and test for svc 0 + bnz BASED(sysc_nr_ok) # svc number > 0 # svc 0: system call number in %r1 cl %r1,BASED(.Lnr_syscalls) bnl BASED(sysc_nr_ok) - lr %r7,%r1 # copy svc number to %r7 - sla %r7,2 # *4 + lr %r7,%r1 # copy svc number to %r7 + sla %r7,2 # *4 sysc_nr_ok: mvc SP_ARGS(4,%r15),SP_R7(%r15) sysc_do_restart: l %r8,BASED(.Lsysc_table) tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) l %r8,0(%r7,%r8) # get system call addr. - 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 - # changing anything here !! + 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 + # changing anything here !! sysc_return: tm SP_PSW+1(%r15),0x01 # returning to user ? @@ -258,14 +258,14 @@ sysc_return: tm __TI_flags+3(%r9),_TIF_WORK_SVC bnz BASED(sysc_work) # there is work to do (signals etc.) sysc_leave: - RESTORE_ALL __LC_RETURN_PSW,1 + RESTORE_ALL __LC_RETURN_PSW,1 # # recheck if there is more work to do # sysc_work_loop: tm __TI_flags+3(%r9),_TIF_WORK_SVC - bz BASED(sysc_leave) # there is no work to do + bz BASED(sysc_leave) # there is no work to do # # One of the work bits is on. Find out which one. # @@ -284,11 +284,11 @@ sysc_work: # # _TIF_NEED_RESCHED is set, call schedule -# -sysc_reschedule: - l %r1,BASED(.Lschedule) - la %r14,BASED(sysc_work_loop) - br %r1 # call scheduler +# +sysc_reschedule: + l %r1,BASED(.Lschedule) + la %r14,BASED(sysc_work_loop) + br %r1 # call scheduler # # _TIF_MCCK_PENDING is set, call handler @@ -301,11 +301,11 @@ sysc_mcck_pending: # # _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal # -sysc_sigpending: +sysc_sigpending: ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP - la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,BASED(.Ldo_signal) - basr %r14,%r1 # call do_signal + la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Ldo_signal) + basr %r14,%r1 # call do_signal tm __TI_flags+3(%r9),_TIF_RESTART_SVC bo BASED(sysc_restart) tm __TI_flags+3(%r9),_TIF_SINGLE_STEP @@ -317,11 +317,11 @@ sysc_sigpending: # sysc_restart: ni __TI_flags+3(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC - l %r7,SP_R2(%r15) # load new svc number + l %r7,SP_R2(%r15) # load new svc number sla %r7,2 mvc SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument - lm %r2,%r6,SP_R2(%r15) # load svc arguments - b BASED(sysc_do_restart) # restart svc + lm %r2,%r6,SP_R2(%r15) # load svc arguments + b BASED(sysc_do_restart) # restart svc # # _TIF_SINGLE_STEP is set, call do_single_step @@ -338,8 +338,8 @@ sysc_singlestep: # call trace before and after sys_call # sysc_tracesys: - l %r1,BASED(.Ltrace) - la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Ltrace) + la %r2,SP_PTREGS(%r15) # load pt_regs la %r3,0 srl %r7,2 st %r7,SP_R2(%r15) @@ -347,19 +347,19 @@ sysc_tracesys: clc SP_R2(4,%r15),BASED(.Lnr_syscalls) bnl BASED(sysc_tracenogo) l %r8,BASED(.Lsysc_table) - l %r7,SP_R2(%r15) # strace might have changed the - sll %r7,2 # system call + l %r7,SP_R2(%r15) # strace might have changed the + sll %r7,2 # system call l %r8,0(%r7,%r8) sysc_tracego: 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 + basr %r14,%r8 # call sys_xxx + st %r2,SP_R2(%r15) # store return value sysc_tracenogo: tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) - bz BASED(sysc_return) + bz BASED(sysc_return) l %r1,BASED(.Ltrace) - la %r2,SP_PTREGS(%r15) # load pt_regs + la %r2,SP_PTREGS(%r15) # load pt_regs la %r3,1 la %r14,BASED(sysc_return) br %r1 @@ -367,17 +367,17 @@ sysc_tracenogo: # # a new process exits the kernel with ret_from_fork # - .globl ret_from_fork + .globl ret_from_fork ret_from_fork: l %r13,__LC_SVC_NEW_PSW+4 l %r9,__LC_THREAD_INFO # load pointer to thread_info struct tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? bo BASED(0f) st %r15,SP_R15(%r15) # store stack pointer for new kthread -0: l %r1,BASED(.Lschedtail) - basr %r14,%r1 +0: l %r1,BASED(.Lschedtail) + basr %r14,%r1 TRACE_IRQS_ON - stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts b BASED(sysc_return) # @@ -386,52 +386,51 @@ ret_from_fork: # but are called with different parameter. # return-address is set up above # -sys_clone_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,BASED(.Lclone) - br %r1 # branch to sys_clone - -sys_fork_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,BASED(.Lfork) - br %r1 # branch to sys_fork - -sys_vfork_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,BASED(.Lvfork) - br %r1 # branch to sys_vfork - -sys_execve_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,BASED(.Lexecve) - lr %r12,%r14 # save return address - basr %r14,%r1 # call sys_execve - ltr %r2,%r2 # check if execve failed - bnz 0(%r12) # it did fail -> store result in gpr2 - b 4(%r12) # SKIP ST 2,SP_R2(15) after BASR 14,8 - # in system_call/sysc_tracesys - -sys_sigreturn_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs as parameter - 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,BASED(.Lrt_sigreturn) - br %r1 # branch to sys_sigreturn +sys_clone_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Lclone) + br %r1 # branch to sys_clone -sys_sigaltstack_glue: - la %r4,SP_PTREGS(%r15) # load pt_regs as parameter - l %r1,BASED(.Lsigaltstack) - br %r1 # branch to sys_sigreturn +sys_fork_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Lfork) + br %r1 # branch to sys_fork +sys_vfork_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Lvfork) + br %r1 # branch to sys_vfork + +sys_execve_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Lexecve) + lr %r12,%r14 # save return address + basr %r14,%r1 # call sys_execve + ltr %r2,%r2 # check if execve failed + bnz 0(%r12) # it did fail -> store result in gpr2 + b 4(%r12) # SKIP ST 2,SP_R2(15) after BASR 14,8 + # in system_call/sysc_tracesys + +sys_sigreturn_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + 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,BASED(.Lrt_sigreturn) + br %r1 # branch to sys_sigreturn + +sys_sigaltstack_glue: + la %r4,SP_PTREGS(%r15) # load pt_regs as parameter + l %r1,BASED(.Lsigaltstack) + br %r1 # branch to sys_sigreturn /* * Program check handler routine */ - .globl pgm_check_handler + .globl pgm_check_handler pgm_check_handler: /* * First we need to check for a special case: @@ -448,8 +447,8 @@ pgm_check_handler: */ STORE_TIMER __LC_SYNC_ENTER_TIMER SAVE_ALL_BASE __LC_SAVE_AREA - tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception - bnz BASED(pgm_per) # got per exception -> special case + tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception + bnz BASED(pgm_per) # got per exception -> special case SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA #ifdef CONFIG_VIRT_CPU_ACCOUNTING @@ -461,29 +460,29 @@ pgm_check_handler: pgm_no_vtime: #endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct - l %r3,__LC_PGM_ILC # load program interruption code + l %r3,__LC_PGM_ILC # load program interruption code la %r8,0x7f nr %r8,%r3 pgm_do_call: - l %r7,BASED(.Ljump_table) - sll %r8,2 - l %r7,0(%r8,%r7) # load address of handler routine - la %r2,SP_PTREGS(%r15) # address of register-save area - la %r14,BASED(sysc_return) - br %r7 # branch to interrupt-handler + l %r7,BASED(.Ljump_table) + sll %r8,2 + l %r7,0(%r8,%r7) # load address of handler routine + la %r2,SP_PTREGS(%r15) # address of register-save area + la %r14,BASED(sysc_return) + br %r7 # branch to interrupt-handler # # handle per exception # pgm_per: - tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on - bnz BASED(pgm_per_std) # ok, normal per event from user space + tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on + bnz BASED(pgm_per_std) # ok, normal per event from user space # 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 - be BASED(pgm_svcper) + clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW + be BASED(pgm_svcper) # no interesting special case, ignore PER event - lm %r12,%r15,__LC_SAVE_AREA - lpsw 0x28 + lm %r12,%r15,__LC_SAVE_AREA + lpsw 0x28 # # Normal per exception @@ -505,10 +504,12 @@ pgm_no_vtime2: mvc __THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP - l %r3,__LC_PGM_ILC # load program interruption code + tm SP_PSW+1(%r15),0x01 # kernel per event ? + bz BASED(kernel_per) + l %r3,__LC_PGM_ILC # load program interruption code la %r8,0x7f - nr %r8,%r3 # clear per-event-bit and ilc - be BASED(sysc_return) # only per or per+check ? + nr %r8,%r3 # clear per-event-bit and ilc + be BASED(sysc_return) # only per or per+check ? b BASED(pgm_do_call) # @@ -536,11 +537,21 @@ pgm_no_vtime3: stosm __SF_EMPTY(%r15),0x03 # reenable interrupts b BASED(sysc_do_svc) +# +# per was called from kernel, must be kprobes +# +kernel_per: + mvi SP_TRAP+1(%r15),0x28 # set trap indication to pgm check + la %r2,SP_PTREGS(%r15) # address of register-save area + l %r1,BASED(.Lhandle_per) # load adr. of per handler + la %r14,BASED(sysc_leave) # load adr. of system return + br %r1 # branch to do_single_step + /* * IO interrupt handler routine */ - .globl io_int_handler + .globl io_int_handler io_int_handler: STORE_TIMER __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK @@ -557,42 +568,42 @@ io_no_vtime: #endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF - l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ - la %r2,SP_PTREGS(%r15) # address of register-save area - basr %r14,%r1 # branch to standard irq handler + l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ + la %r2,SP_PTREGS(%r15) # address of register-save area + basr %r14,%r1 # branch to standard irq handler TRACE_IRQS_ON io_return: - tm SP_PSW+1(%r15),0x01 # returning to user ? + tm SP_PSW+1(%r15),0x01 # returning to user ? #ifdef CONFIG_PREEMPT - bno BASED(io_preempt) # no -> check for preemptive scheduling + bno BASED(io_preempt) # no -> check for preemptive scheduling #else - bno BASED(io_leave) # no-> skip resched & signal + bno BASED(io_leave) # no-> skip resched & signal #endif tm __TI_flags+3(%r9),_TIF_WORK_INT - bnz BASED(io_work) # there is work to do (signals etc.) + bnz BASED(io_work) # there is work to do (signals etc.) io_leave: - RESTORE_ALL __LC_RETURN_PSW,0 + RESTORE_ALL __LC_RETURN_PSW,0 io_done: #ifdef CONFIG_PREEMPT io_preempt: icm %r0,15,__TI_precount(%r9) - bnz BASED(io_leave) + bnz BASED(io_leave) l %r1,SP_R15(%r15) s %r1,BASED(.Lc_spsize) mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain + xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain lr %r15,%r1 io_resume_loop: tm __TI_flags+3(%r9),_TIF_NEED_RESCHED bno BASED(io_leave) - mvc __TI_precount(4,%r9),BASED(.Lc_pactive) - stosm __SF_EMPTY(%r15),0x03 # reenable interrupts - l %r1,BASED(.Lschedule) + mvc __TI_precount(4,%r9),BASED(.Lc_pactive) + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + l %r1,BASED(.Lschedule) basr %r14,%r1 # call schedule - stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts - xc __TI_precount(4,%r9),__TI_precount(%r9) + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts + xc __TI_precount(4,%r9),__TI_precount(%r9) b BASED(io_resume_loop) #endif @@ -603,16 +614,16 @@ io_work: l %r1,__LC_KERNEL_STACK s %r1,BASED(.Lc_spsize) mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain + xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain lr %r15,%r1 # # One of the work bits is on. Find out which one. # Checked are: _TIF_SIGPENDING, _TIF_RESTORE_SIGMASK, _TIF_NEED_RESCHED -# and _TIF_MCCK_PENDING +# and _TIF_MCCK_PENDING # io_work_loop: tm __TI_flags+3(%r9),_TIF_MCCK_PENDING - bo BASED(io_mcck_pending) + bo BASED(io_mcck_pending) tm __TI_flags+3(%r9),_TIF_NEED_RESCHED bo BASED(io_reschedule) tm __TI_flags+3(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK) @@ -625,36 +636,36 @@ io_work_loop: io_mcck_pending: l %r1,BASED(.Ls390_handle_mcck) la %r14,BASED(io_work_loop) - br %r1 # TIF bit will be cleared by handler + br %r1 # TIF bit will be cleared by handler # # _TIF_NEED_RESCHED is set, call schedule -# -io_reschedule: - l %r1,BASED(.Lschedule) - stosm __SF_EMPTY(%r15),0x03 # reenable interrupts - basr %r14,%r1 # call scheduler - stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts +# +io_reschedule: + l %r1,BASED(.Lschedule) + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + basr %r14,%r1 # call scheduler + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts tm __TI_flags+3(%r9),_TIF_WORK_INT - bz BASED(io_leave) # there is no work to do + bz BASED(io_leave) # there is no work to do b BASED(io_work_loop) # # _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal # -io_sigpending: - stosm __SF_EMPTY(%r15),0x03 # reenable interrupts - la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,BASED(.Ldo_signal) - basr %r14,%r1 # call do_signal - stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts +io_sigpending: + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + la %r2,SP_PTREGS(%r15) # load pt_regs + l %r1,BASED(.Ldo_signal) + basr %r14,%r1 # call do_signal + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts b BASED(io_work_loop) /* * External interrupt handler routine */ - .globl ext_int_handler + .globl ext_int_handler ext_int_handler: STORE_TIMER __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK @@ -671,8 +682,8 @@ ext_no_vtime: #endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF - la %r2,SP_PTREGS(%r15) # address of register-save area - lh %r3,__LC_EXT_INT_CODE # get interruption code + la %r2,SP_PTREGS(%r15) # address of register-save area + lh %r3,__LC_EXT_INT_CODE # get interruption code l %r1,BASED(.Ldo_extint) basr %r14,%r1 TRACE_IRQS_ON @@ -684,13 +695,13 @@ __critical_end: * Machine check handler routines */ - .globl mcck_int_handler + .globl mcck_int_handler mcck_int_handler: spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs SAVE_ALL_BASE __LC_SAVE_AREA+32 la %r12,__LC_MCK_OLD_PSW - tm __LC_MCCK_CODE,0x80 # system damage? + tm __LC_MCCK_CODE,0x80 # system damage? bo BASED(mcck_int_main) # yes -> rest of mcck code invalid #ifdef CONFIG_VIRT_CPU_ACCOUNTING mvc __LC_SAVE_AREA+52(8),__LC_ASYNC_ENTER_TIMER @@ -729,7 +740,7 @@ mcck_int_main: l %r15,__LC_PANIC_STACK # load panic stack 0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32 #ifdef CONFIG_VIRT_CPU_ACCOUNTING - tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? + tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? bno BASED(mcck_no_vtime) # no -> skip cleanup critical tm SP_PSW+1(%r15),0x01 # interrupting from user ? bz BASED(mcck_no_vtime) @@ -740,14 +751,14 @@ mcck_no_vtime: #endif l %r9,__LC_THREAD_INFO # load pointer to thread_info struct la %r2,SP_PTREGS(%r15) # load pt_regs - l %r1,BASED(.Ls390_mcck) - basr %r14,%r1 # call machine check handler - tm SP_PSW+1(%r15),0x01 # returning to user ? + l %r1,BASED(.Ls390_mcck) + basr %r14,%r1 # call machine check handler + tm SP_PSW+1(%r15),0x01 # returning to user ? bno BASED(mcck_return) - l %r1,__LC_KERNEL_STACK # switch to kernel stack + l %r1,__LC_KERNEL_STACK # switch to kernel stack s %r1,BASED(.Lc_spsize) mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain + xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain lr %r15,%r1 stosm __SF_EMPTY(%r15),0x04 # turn dat on tm __TI_flags+3(%r9),_TIF_MCCK_PENDING @@ -771,36 +782,36 @@ mcck_return: lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 lpsw __LC_RETURN_MCCK_PSW # back to caller - RESTORE_ALL __LC_RETURN_MCCK_PSW,0 + RESTORE_ALL __LC_RETURN_MCCK_PSW,0 #ifdef CONFIG_SMP /* * Restart interruption handler, kick starter for additional CPUs */ - .globl restart_int_handler + .globl restart_int_handler restart_int_handler: - l %r15,__LC_SAVE_AREA+60 # load ksp - lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs - lam %a0,%a15,__LC_AREGS_SAVE_AREA - lm %r6,%r15,__SF_GPRS(%r15) # load registers from clone - stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on - basr %r14,0 - l %r14,restart_addr-.(%r14) - br %r14 # branch to start_secondary + l %r15,__LC_SAVE_AREA+60 # load ksp + lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs + lam %a0,%a15,__LC_AREGS_SAVE_AREA + lm %r6,%r15,__SF_GPRS(%r15) # load registers from clone + stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on + basr %r14,0 + l %r14,restart_addr-.(%r14) + br %r14 # branch to start_secondary restart_addr: - .long start_secondary + .long start_secondary #else /* * If we do not run with SMP enabled, let the new CPU crash ... */ - .globl restart_int_handler + .globl restart_int_handler restart_int_handler: - basr %r1,0 + basr %r1,0 restart_base: - lpsw restart_crash-restart_base(%r1) - .align 8 + lpsw restart_crash-restart_base(%r1) + .align 8 restart_crash: - .long 0x000a0000,0x00000000 + .long 0x000a0000,0x00000000 restart_go: #endif @@ -822,11 +833,11 @@ stack_overflow: be BASED(0f) la %r1,__LC_SAVE_AREA+16 0: mvc SP_R12(16,%r15),0(%r1) # move %r12-%r15 to stack - xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear back chain + xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear back chain l %r1,BASED(1f) # branch to kernel_stack_overflow - la %r2,SP_PTREGS(%r15) # load pt_regs + la %r2,SP_PTREGS(%r15) # load pt_regs br %r1 -1: .long kernel_stack_overflow +1: .long kernel_stack_overflow #endif cleanup_table_system_call: @@ -928,10 +939,10 @@ cleanup_novtime: cleanup_system_call_insn: .long sysc_saveall + 0x80000000 #ifdef CONFIG_VIRT_CPU_ACCOUNTING - .long system_call + 0x80000000 - .long sysc_vtime + 0x80000000 - .long sysc_stime + 0x80000000 - .long sysc_update + 0x80000000 + .long system_call + 0x80000000 + .long sysc_vtime + 0x80000000 + .long sysc_stime + 0x80000000 + .long sysc_update + 0x80000000 #endif cleanup_sysc_return: @@ -997,57 +1008,57 @@ cleanup_io_leave_insn: /* * Integer constants */ - .align 4 -.Lc_spsize: .long SP_SIZE -.Lc_overhead: .long STACK_FRAME_OVERHEAD -.Lc_pactive: .long PREEMPT_ACTIVE -.Lnr_syscalls: .long NR_syscalls -.L0x018: .short 0x018 -.L0x020: .short 0x020 -.L0x028: .short 0x028 -.L0x030: .short 0x030 -.L0x038: .short 0x038 -.Lc_1: .long 1 + .align 4 +.Lc_spsize: .long SP_SIZE +.Lc_overhead: .long STACK_FRAME_OVERHEAD +.Lc_pactive: .long PREEMPT_ACTIVE +.Lnr_syscalls: .long NR_syscalls +.L0x018: .short 0x018 +.L0x020: .short 0x020 +.L0x028: .short 0x028 +.L0x030: .short 0x030 +.L0x038: .short 0x038 +.Lc_1: .long 1 /* * Symbol constants */ -.Ls390_mcck: .long s390_do_machine_check +.Ls390_mcck: .long s390_do_machine_check .Ls390_handle_mcck: - .long s390_handle_mcck -.Lmck_old_psw: .long __LC_MCK_OLD_PSW -.Ldo_IRQ: .long do_IRQ -.Ldo_extint: .long do_extint -.Ldo_signal: .long do_signal -.Lhandle_per: .long do_single_step -.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 + .long s390_handle_mcck +.Lmck_old_psw: .long __LC_MCK_OLD_PSW +.Ldo_IRQ: .long do_IRQ +.Ldo_extint: .long do_extint +.Ldo_signal: .long do_signal +.Lhandle_per: .long do_single_step +.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 -.Lschedtail: .long schedule_tail -.Lsysc_table: .long sys_call_table + .long sys_rt_sigsuspend +.Lsigreturn: .long sys_sigreturn +.Lsigsuspend: .long sys_sigsuspend +.Lsigaltstack: .long sys_sigaltstack +.Ltrace: .long syscall_trace +.Lvfork: .long sys_vfork +.Lschedtail: .long schedule_tail +.Lsysc_table: .long sys_call_table #ifdef CONFIG_TRACE_IRQFLAGS -.Ltrace_irq_on:.long trace_hardirqs_on +.Ltrace_irq_on: .long trace_hardirqs_on .Ltrace_irq_off: - .long trace_hardirqs_off + .long trace_hardirqs_off #endif .Lcritical_start: - .long __critical_start + 0x80000000 + .long __critical_start + 0x80000000 .Lcritical_end: - .long __critical_end + 0x80000000 + .long __critical_end + 0x80000000 .Lcleanup_critical: - .long cleanup_critical + .long cleanup_critical - .section .rodata, "a" + .section .rodata, "a" #define SYSCALL(esa,esame,emu) .long esa sys_call_table: #include "syscalls.S" diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index 56f5f613b868..0f758c329a5d 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -4,8 +4,8 @@ * * Copyright (C) IBM Corp. 1999,2006 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), - * Hartmut Penner (hp@de.ibm.com), - * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), + * Hartmut Penner (hp@de.ibm.com), + * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com), * Heiko Carstens <heiko.carstens@de.ibm.com> */ @@ -24,29 +24,29 @@ * Stack layout for the system_call stack entry. * The first few entries are identical to the user_regs_struct. */ -SP_PTREGS = STACK_FRAME_OVERHEAD -SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS -SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW -SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS -SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8 -SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16 -SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24 -SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32 -SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40 -SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48 -SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56 -SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 64 -SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 72 -SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 80 -SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 88 -SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 96 -SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 104 -SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112 -SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120 -SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 -SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC -SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP -SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE +SP_PTREGS = STACK_FRAME_OVERHEAD +SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS +SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW +SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS +SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8 +SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16 +SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24 +SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32 +SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40 +SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48 +SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56 +SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 64 +SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 72 +SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 80 +SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 88 +SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 96 +SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 104 +SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112 +SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120 +SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2 +SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC +SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP +SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER STACK_SIZE = 1 << STACK_SHIFT @@ -71,14 +71,14 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \ #define TRACE_IRQS_OFF #endif - .macro STORE_TIMER lc_offset + .macro STORE_TIMER lc_offset #ifdef CONFIG_VIRT_CPU_ACCOUNTING stpt \lc_offset #endif .endm #ifdef CONFIG_VIRT_CPU_ACCOUNTING - .macro UPDATE_VTIME lc_from,lc_to,lc_sum + .macro UPDATE_VTIME lc_from,lc_to,lc_sum lg %r10,\lc_from slg %r10,\lc_to alg %r10,\lc_sum @@ -94,7 +94,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \ * R15 - kernel stack pointer */ - .macro SAVE_ALL_BASE savearea + .macro SAVE_ALL_BASE savearea stmg %r12,%r15,\savearea larl %r13,system_call .endm @@ -139,8 +139,8 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \ .endm .macro CREATE_STACK_FRAME psworg,savearea - aghi %r15,-SP_SIZE # make room for registers & psw - mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack + aghi %r15,-SP_SIZE # make room for registers & psw + mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack la %r12,\psworg stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2 icm %r12,12,__LC_SVC_ILC @@ -149,7 +149,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \ mvc SP_R12(32,%r15),\savearea # move %r12-%r15 to stack la %r12,0 stg %r12,__SF_BACKCHAIN(%r15) - .endm + .endm .macro RESTORE_ALL psworg,sync mvc \psworg(16),SP_PSW(%r15) # move user PSW to lowcore @@ -168,29 +168,29 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \ * Returns: * gpr2 = prev */ - .globl __switch_to + .globl __switch_to __switch_to: tm __THREAD_per+4(%r3),0xe8 # is the new process using per ? jz __switch_to_noper # if not we're fine - stctg %c9,%c11,__SF_EMPTY(%r15)# We are using per stuff - clc __THREAD_per(24,%r3),__SF_EMPTY(%r15) - je __switch_to_noper # we got away without bashing TLB's - lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't + stctg %c9,%c11,__SF_EMPTY(%r15)# We are using per stuff + clc __THREAD_per(24,%r3),__SF_EMPTY(%r15) + je __switch_to_noper # we got away without bashing TLB's + lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't __switch_to_noper: - lg %r4,__THREAD_info(%r2) # get thread_info of prev + lg %r4,__THREAD_info(%r2) # get thread_info of prev tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending? jz __switch_to_no_mcck ni __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev lg %r4,__THREAD_info(%r3) # get thread_info of next oi __TI_flags+7(%r4),_TIF_MCCK_PENDING # set it in next __switch_to_no_mcck: - stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task + stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp - lmg %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task + lmg %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task stg %r3,__LC_CURRENT # __LC_CURRENT = current task struct lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4 - lg %r3,__THREAD_info(%r3) # load thread_info from task struct + lg %r3,__THREAD_info(%r3) # load thread_info from task struct stg %r3,__LC_THREAD_INFO aghi %r3,STACK_SIZE stg %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack @@ -202,14 +202,14 @@ __critical_start: * are executed with interrupts enabled. */ - .globl system_call + .globl system_call system_call: STORE_TIMER __LC_SYNC_ENTER_TIMER sysc_saveall: SAVE_ALL_BASE __LC_SAVE_AREA SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA - CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA - llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore + CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA + llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore #ifdef CONFIG_VIRT_CPU_ACCOUNTING sysc_vtime: tm SP_PSW+1(%r15),0x01 # interrupting from user ? @@ -222,45 +222,45 @@ sysc_update: #endif sysc_do_svc: lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct - slag %r7,%r7,2 # *4 and test for svc 0 + slag %r7,%r7,2 # *4 and test for svc 0 jnz sysc_nr_ok # svc 0: system call number in %r1 cl %r1,BASED(.Lnr_syscalls) jnl sysc_nr_ok - lgfr %r7,%r1 # clear high word in r1 - slag %r7,%r7,2 # svc 0: system call number in %r1 + lgfr %r7,%r1 # clear high word in r1 + slag %r7,%r7,2 # svc 0: system call number in %r1 sysc_nr_ok: mvc SP_ARGS(8,%r15),SP_R7(%r15) sysc_do_restart: - larl %r10,sys_call_table + larl %r10,sys_call_table #ifdef CONFIG_COMPAT tm __TI_flags+5(%r9),(_TIF_31BIT>>16) # running in 31 bit mode ? jno sysc_noemu - larl %r10,sys_call_table_emu # use 31 bit emulation system calls + larl %r10,sys_call_table_emu # use 31 bit emulation system calls sysc_noemu: #endif tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) - lgf %r8,0(%r7,%r10) # load address of system call routine - jnz sysc_tracesys - basr %r14,%r8 # call sys_xxxx - stg %r2,SP_R2(%r15) # store return value (change R2 on stack) - # ATTENTION: check sys_execve_glue before - # changing anything here !! + lgf %r8,0(%r7,%r10) # load address of system call routine + jnz sysc_tracesys + basr %r14,%r8 # call sys_xxxx + stg %r2,SP_R2(%r15) # store return value (change R2 on stack) + # ATTENTION: check sys_execve_glue before + # changing anything here !! sysc_return: - tm SP_PSW+1(%r15),0x01 # returning to user ? - jno sysc_leave + tm SP_PSW+1(%r15),0x01 # returning to user ? + jno sysc_leave tm __TI_flags+7(%r9),_TIF_WORK_SVC - jnz sysc_work # there is work to do (signals etc.) + jnz sysc_work # there is work to do (signals etc.) sysc_leave: - RESTORE_ALL __LC_RETURN_PSW,1 + RESTORE_ALL __LC_RETURN_PSW,1 # # recheck if there is more work to do # sysc_work_loop: tm __TI_flags+7(%r9),_TIF_WORK_SVC - jz sysc_leave # there is no work to do + jz sysc_leave # there is no work to do # # One of the work bits is on. Find out which one. # @@ -279,25 +279,25 @@ sysc_work: # # _TIF_NEED_RESCHED is set, call schedule -# -sysc_reschedule: - larl %r14,sysc_work_loop - jg schedule # return point is sysc_return +# +sysc_reschedule: + larl %r14,sysc_work_loop + jg schedule # return point is sysc_return # # _TIF_MCCK_PENDING is set, call handler # sysc_mcck_pending: larl %r14,sysc_work_loop - jg s390_handle_mcck # TIF bit will be cleared by handler + jg s390_handle_mcck # TIF bit will be cleared by handler # # _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal # -sysc_sigpending: +sysc_sigpending: ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP - la %r2,SP_PTREGS(%r15) # load pt_regs - brasl %r14,do_signal # call do_signal + la %r2,SP_PTREGS(%r15) # load pt_regs + brasl %r14,do_signal # call do_signal tm __TI_flags+7(%r9),_TIF_RESTART_SVC jo sysc_restart tm __TI_flags+7(%r9),_TIF_SINGLE_STEP @@ -309,11 +309,11 @@ sysc_sigpending: # sysc_restart: ni __TI_flags+7(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC - lg %r7,SP_R2(%r15) # load new svc number - slag %r7,%r7,2 # *4 + lg %r7,SP_R2(%r15) # load new svc number + slag %r7,%r7,2 # *4 mvc SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument - lmg %r2,%r6,SP_R2(%r15) # load svc arguments - j sysc_do_restart # restart svc + lmg %r2,%r6,SP_R2(%r15) # load svc arguments + j sysc_do_restart # restart svc # # _TIF_SINGLE_STEP is set, call do_single_step @@ -326,49 +326,48 @@ sysc_singlestep: larl %r14,sysc_return # load adr. of system return jg do_single_step # branch to do_sigtrap - # # call syscall_trace before and after system call # special linkage: %r12 contains the return address for trace_svc # sysc_tracesys: - la %r2,SP_PTREGS(%r15) # load pt_regs + la %r2,SP_PTREGS(%r15) # load pt_regs la %r3,0 srl %r7,2 - stg %r7,SP_R2(%r15) - brasl %r14,syscall_trace + stg %r7,SP_R2(%r15) + brasl %r14,syscall_trace lghi %r0,NR_syscalls clg %r0,SP_R2(%r15) jnh sysc_tracenogo - lg %r7,SP_R2(%r15) # strace might have changed the - sll %r7,2 # system call + lg %r7,SP_R2(%r15) # strace might have changed the + sll %r7,2 # system call lgf %r8,0(%r7,%r10) sysc_tracego: - lmg %r3,%r6,SP_R3(%r15) - lg %r2,SP_ORIG_R2(%r15) - basr %r14,%r8 # call sys_xxx - stg %r2,SP_R2(%r15) # store return value + lmg %r3,%r6,SP_R3(%r15) + lg %r2,SP_ORIG_R2(%r15) + basr %r14,%r8 # call sys_xxx + stg %r2,SP_R2(%r15) # store return value sysc_tracenogo: tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT) - jz sysc_return - la %r2,SP_PTREGS(%r15) # load pt_regs + jz sysc_return + la %r2,SP_PTREGS(%r15) # load pt_regs la %r3,1 - larl %r14,sysc_return # return point is sysc_return + larl %r14,sysc_return # return point is sysc_return jg syscall_trace # # a new process exits the kernel with ret_from_fork # - .globl ret_from_fork + .globl ret_from_fork ret_from_fork: lg %r13,__LC_SVC_NEW_PSW+8 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct tm SP_PSW+1(%r15),0x01 # forking a kernel thread ? jo 0f stg %r15,SP_R15(%r15) # store stack pointer for new kthread -0: brasl %r14,schedule_tail +0: brasl %r14,schedule_tail TRACE_IRQS_ON - stosm 24(%r15),0x03 # reenable interrupts + stosm 24(%r15),0x03 # reenable interrupts j sysc_return # @@ -377,78 +376,78 @@ ret_from_fork: # but are called with different parameter. # return-address is set up above # -sys_clone_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs - jg sys_clone # branch to sys_clone +sys_clone_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + jg sys_clone # branch to sys_clone #ifdef CONFIG_COMPAT -sys32_clone_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs - jg sys32_clone # branch to sys32_clone +sys32_clone_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + jg sys32_clone # branch to sys32_clone #endif -sys_fork_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs - jg sys_fork # branch to sys_fork - -sys_vfork_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs - jg sys_vfork # branch to sys_vfork - -sys_execve_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs - lgr %r12,%r14 # save return address - brasl %r14,sys_execve # call sys_execve - ltgr %r2,%r2 # check if execve failed - bnz 0(%r12) # it did fail -> store result in gpr2 - b 6(%r12) # SKIP STG 2,SP_R2(15) in - # system_call/sysc_tracesys +sys_fork_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + jg sys_fork # branch to sys_fork + +sys_vfork_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + jg sys_vfork # branch to sys_vfork + +sys_execve_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + lgr %r12,%r14 # save return address + brasl %r14,sys_execve # call sys_execve + ltgr %r2,%r2 # check if execve failed + bnz 0(%r12) # it did fail -> store result in gpr2 + b 6(%r12) # SKIP STG 2,SP_R2(15) in + # system_call/sysc_tracesys #ifdef CONFIG_COMPAT -sys32_execve_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs - lgr %r12,%r14 # save return address - brasl %r14,sys32_execve # call sys32_execve - ltgr %r2,%r2 # check if execve failed - bnz 0(%r12) # it did fail -> store result in gpr2 - b 6(%r12) # SKIP STG 2,SP_R2(15) in - # system_call/sysc_tracesys +sys32_execve_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs + lgr %r12,%r14 # save return address + brasl %r14,sys32_execve # call sys32_execve + ltgr %r2,%r2 # check if execve failed + bnz 0(%r12) # it did fail -> store result in gpr2 + b 6(%r12) # SKIP STG 2,SP_R2(15) in + # system_call/sysc_tracesys #endif -sys_sigreturn_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs as parameter - jg sys_sigreturn # branch to sys_sigreturn +sys_sigreturn_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + jg sys_sigreturn # branch to sys_sigreturn #ifdef CONFIG_COMPAT -sys32_sigreturn_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs as parameter - jg sys32_sigreturn # branch to sys32_sigreturn +sys32_sigreturn_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + jg sys32_sigreturn # branch to sys32_sigreturn #endif -sys_rt_sigreturn_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs as parameter - jg sys_rt_sigreturn # branch to sys_sigreturn +sys_rt_sigreturn_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + jg sys_rt_sigreturn # branch to sys_sigreturn #ifdef CONFIG_COMPAT -sys32_rt_sigreturn_glue: - la %r2,SP_PTREGS(%r15) # load pt_regs as parameter - jg sys32_rt_sigreturn # branch to sys32_sigreturn +sys32_rt_sigreturn_glue: + la %r2,SP_PTREGS(%r15) # load pt_regs as parameter + jg sys32_rt_sigreturn # branch to sys32_sigreturn #endif sys_sigaltstack_glue: - la %r4,SP_PTREGS(%r15) # load pt_regs as parameter - jg sys_sigaltstack # branch to sys_sigreturn + la %r4,SP_PTREGS(%r15) # load pt_regs as parameter + jg sys_sigaltstack # branch to sys_sigreturn #ifdef CONFIG_COMPAT sys32_sigaltstack_glue: - la %r4,SP_PTREGS(%r15) # load pt_regs as parameter - jg sys32_sigaltstack_wrapper # branch to sys_sigreturn + la %r4,SP_PTREGS(%r15) # load pt_regs as parameter + jg sys32_sigaltstack_wrapper # branch to sys_sigreturn #endif /* * Program check handler routine */ - .globl pgm_check_handler + .globl pgm_check_handler pgm_check_handler: /* * First we need to check for a special case: @@ -465,8 +464,8 @@ pgm_check_handler: */ STORE_TIMER __LC_SYNC_ENTER_TIMER SAVE_ALL_BASE __LC_SAVE_AREA - tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception - jnz pgm_per # got per exception -> special case + tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception + jnz pgm_per # got per exception -> special case SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA #ifdef CONFIG_VIRT_CPU_ACCOUNTING @@ -478,29 +477,29 @@ pgm_check_handler: pgm_no_vtime: #endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct - lgf %r3,__LC_PGM_ILC # load program interruption code + lgf %r3,__LC_PGM_ILC # load program interruption code lghi %r8,0x7f ngr %r8,%r3 pgm_do_call: - sll %r8,3 - larl %r1,pgm_check_table - lg %r1,0(%r8,%r1) # load address of handler routine - la %r2,SP_PTREGS(%r15) # address of register-save area + sll %r8,3 + larl %r1,pgm_check_table + lg %r1,0(%r8,%r1) # load address of handler routine + la %r2,SP_PTREGS(%r15) # address of register-save area larl %r14,sysc_return - br %r1 # branch to interrupt-handler + br %r1 # branch to interrupt-handler # # handle per exception # pgm_per: - tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on - jnz pgm_per_std # ok, normal per event from user space + tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on + jnz pgm_per_std # ok, normal per event from user space # ok its one of the special cases, now we need to find out which one - clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW - je pgm_svcper + clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW + je pgm_svcper # no interesting special case, ignore PER event lmg %r12,%r15,__LC_SAVE_AREA - lpswe __LC_PGM_OLD_PSW + lpswe __LC_PGM_OLD_PSW # # Normal per exception @@ -518,13 +517,15 @@ pgm_no_vtime2: #endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r1,__TI_task(%r9) + tm SP_PSW+1(%r15),0x01 # kernel per event ? + jz kernel_per mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP - lgf %r3,__LC_PGM_ILC # load program interruption code + lgf %r3,__LC_PGM_ILC # load program interruption code lghi %r8,0x7f - ngr %r8,%r3 # clear per-event-bit and ilc + ngr %r8,%r3 # clear per-event-bit and ilc je sysc_return j pgm_do_call @@ -542,7 +543,7 @@ pgm_svcper: mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER pgm_no_vtime3: #endif - llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore + llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r1,__TI_task(%r9) mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID @@ -553,10 +554,20 @@ pgm_no_vtime3: stosm __SF_EMPTY(%r15),0x03 # reenable interrupts j sysc_do_svc +# +# per was called from kernel, must be kprobes +# +kernel_per: + lhi %r0,__LC_PGM_OLD_PSW + sth %r0,SP_TRAP(%r15) # set trap indication to pgm check + la %r2,SP_PTREGS(%r15) # address of register-save area + larl %r14,sysc_leave # load adr. of system ret, no work + jg do_single_step # branch to do_single_step + /* * IO interrupt handler routine */ - .globl io_int_handler + .globl io_int_handler io_int_handler: STORE_TIMER __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK @@ -573,42 +584,42 @@ io_no_vtime: #endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF - la %r2,SP_PTREGS(%r15) # address of register-save area - brasl %r14,do_IRQ # call standard irq handler + la %r2,SP_PTREGS(%r15) # address of register-save area + brasl %r14,do_IRQ # call standard irq handler TRACE_IRQS_ON io_return: - tm SP_PSW+1(%r15),0x01 # returning to user ? + tm SP_PSW+1(%r15),0x01 # returning to user ? #ifdef CONFIG_PREEMPT - jno io_preempt # no -> check for preemptive scheduling + jno io_preempt # no -> check for preemptive scheduling #else - jno io_leave # no-> skip resched & signal + jno io_leave # no-> skip resched & signal #endif tm __TI_flags+7(%r9),_TIF_WORK_INT - jnz io_work # there is work to do (signals etc.) + jnz io_work # there is work to do (signals etc.) io_leave: - RESTORE_ALL __LC_RETURN_PSW,0 + RESTORE_ALL __LC_RETURN_PSW,0 io_done: #ifdef CONFIG_PREEMPT io_preempt: - icm %r0,15,__TI_precount(%r9) - jnz io_leave + icm %r0,15,__TI_precount(%r9) + jnz io_leave # switch to kernel stack lg %r1,SP_R15(%r15) aghi %r1,-SP_SIZE mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain + xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain lgr %r15,%r1 io_resume_loop: tm __TI_flags+7(%r9),_TIF_NEED_RESCHED jno io_leave - larl %r1,.Lc_pactive - mvc __TI_precount(4,%r9),0(%r1) - stosm __SF_EMPTY(%r15),0x03 # reenable interrupts - brasl %r14,schedule # call schedule - stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts - xc __TI_precount(4,%r9),__TI_precount(%r9) + larl %r1,.Lc_pactive + mvc __TI_precount(4,%r9),0(%r1) + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + brasl %r14,schedule # call schedule + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts + xc __TI_precount(4,%r9),__TI_precount(%r9) j io_resume_loop #endif @@ -619,7 +630,7 @@ io_work: lg %r1,__LC_KERNEL_STACK aghi %r1,-SP_SIZE mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15) - xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain + xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain lgr %r15,%r1 # # One of the work bits is on. Find out which one. @@ -644,11 +655,11 @@ io_mcck_pending: # # _TIF_NEED_RESCHED is set, call schedule -# -io_reschedule: - stosm __SF_EMPTY(%r15),0x03 # reenable interrupts - brasl %r14,schedule # call scheduler - stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts +# +io_reschedule: + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + brasl %r14,schedule # call scheduler + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts tm __TI_flags+7(%r9),_TIF_WORK_INT jz io_leave # there is no work to do j io_work_loop @@ -656,17 +667,17 @@ io_reschedule: # # _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal # -io_sigpending: - stosm __SF_EMPTY(%r15),0x03 # reenable interrupts - la %r2,SP_PTREGS(%r15) # load pt_regs +io_sigpending: + stosm __SF_EMPTY(%r15),0x03 # reenable interrupts + la %r2,SP_PTREGS(%r15) # load pt_regs brasl %r14,do_signal # call do_signal - stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts + stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts j io_work_loop /* * External interrupt handler routine */ - .globl ext_int_handler + .globl ext_int_handler ext_int_handler: STORE_TIMER __LC_ASYNC_ENTER_TIMER stck __LC_INT_CLOCK @@ -683,9 +694,9 @@ ext_no_vtime: #endif lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct TRACE_IRQS_OFF - la %r2,SP_PTREGS(%r15) # address of register-save area - llgh %r3,__LC_EXT_INT_CODE # get interruption code - brasl %r14,do_extint + la %r2,SP_PTREGS(%r15) # address of register-save area + llgh %r3,__LC_EXT_INT_CODE # get interruption code + brasl %r14,do_extint TRACE_IRQS_ON j io_return @@ -694,14 +705,14 @@ __critical_end: /* * Machine check handler routines */ - .globl mcck_int_handler + .globl mcck_int_handler mcck_int_handler: la %r1,4095 # revalidate r1 spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer - lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs + lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs SAVE_ALL_BASE __LC_SAVE_AREA+64 la %r12,__LC_MCK_OLD_PSW - tm __LC_MCCK_CODE,0x80 # system damage? + tm __LC_MCCK_CODE,0x80 # system damage? jo mcck_int_main # yes -> rest of mcck code invalid #ifdef CONFIG_VIRT_CPU_ACCOUNTING la %r14,4095 @@ -725,19 +736,19 @@ mcck_int_handler: #endif tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? jno mcck_int_main # no -> skip cleanup critical - tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit + tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit jnz mcck_int_main # from user -> load kernel stack clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_end) jhe mcck_int_main - clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start) + clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start) jl mcck_int_main - brasl %r14,cleanup_critical + brasl %r14,cleanup_critical mcck_int_main: - lg %r14,__LC_PANIC_STACK # are we already on the panic stack? + lg %r14,__LC_PANIC_STACK # are we already on the panic stack? slgr %r14,%r15 srag %r14,%r14,PAGE_SHIFT jz 0f - lg %r15,__LC_PANIC_STACK # load panic stack + lg %r15,__LC_PANIC_STACK # load panic stack 0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64 #ifdef CONFIG_VIRT_CPU_ACCOUNTING tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid? @@ -752,7 +763,7 @@ mcck_no_vtime: lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct la %r2,SP_PTREGS(%r15) # load pt_regs brasl %r14,s390_do_machine_check - tm SP_PSW+1(%r15),0x01 # returning to user ? + tm SP_PSW+1(%r15),0x01 # returning to user ? jno mcck_return lg %r1,__LC_KERNEL_STACK # switch to kernel stack aghi %r1,-SP_SIZE @@ -782,28 +793,28 @@ mcck_return: /* * Restart interruption handler, kick starter for additional CPUs */ - .globl restart_int_handler + .globl restart_int_handler restart_int_handler: - lg %r15,__LC_SAVE_AREA+120 # load ksp - lghi %r10,__LC_CREGS_SAVE_AREA - lctlg %c0,%c15,0(%r10) # get new ctl regs - lghi %r10,__LC_AREGS_SAVE_AREA - lam %a0,%a15,0(%r10) - lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone - stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on - jg start_secondary + lg %r15,__LC_SAVE_AREA+120 # load ksp + lghi %r10,__LC_CREGS_SAVE_AREA + lctlg %c0,%c15,0(%r10) # get new ctl regs + lghi %r10,__LC_AREGS_SAVE_AREA + lam %a0,%a15,0(%r10) + lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone + stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on + jg start_secondary #else /* * If we do not run with SMP enabled, let the new CPU crash ... */ - .globl restart_int_handler + .globl restart_int_handler restart_int_handler: - basr %r1,0 + basr %r1,0 restart_base: - lpswe restart_crash-restart_base(%r1) - .align 8 + lpswe restart_crash-restart_base(%r1) + .align 8 restart_crash: - .long 0x000a0000,0x00000000,0x00000000,0x00000000 + .long 0x000a0000,0x00000000,0x00000000,0x00000000 restart_go: #endif @@ -815,7 +826,7 @@ restart_go: */ stack_overflow: lg %r15,__LC_PANIC_STACK # change to panic stack - aghi %r1,-SP_SIZE + aghi %r15,-SP_SIZE mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack stmg %r0,%r11,SP_R0(%r15) # store gprs %r0-%r11 to kernel stack la %r1,__LC_SAVE_AREA @@ -823,10 +834,10 @@ stack_overflow: je 0f chi %r12,__LC_PGM_OLD_PSW je 0f - la %r1,__LC_SAVE_AREA+16 -0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack - xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain - la %r2,SP_PTREGS(%r15) # load pt_regs + la %r1,__LC_SAVE_AREA+32 +0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack + xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain + la %r2,SP_PTREGS(%r15) # load pt_regs jg kernel_stack_overflow #endif @@ -929,10 +940,10 @@ cleanup_novtime: cleanup_system_call_insn: .quad sysc_saveall #ifdef CONFIG_VIRT_CPU_ACCOUNTING - .quad system_call - .quad sysc_vtime - .quad sysc_stime - .quad sysc_update + .quad system_call + .quad sysc_vtime + .quad sysc_stime + .quad sysc_update #endif cleanup_sysc_return: @@ -998,21 +1009,21 @@ cleanup_io_leave_insn: /* * Integer constants */ - .align 4 + .align 4 .Lconst: -.Lc_pactive: .long PREEMPT_ACTIVE -.Lnr_syscalls: .long NR_syscalls -.L0x0130: .short 0x130 -.L0x0140: .short 0x140 -.L0x0150: .short 0x150 -.L0x0160: .short 0x160 -.L0x0170: .short 0x170 +.Lc_pactive: .long PREEMPT_ACTIVE +.Lnr_syscalls: .long NR_syscalls +.L0x0130: .short 0x130 +.L0x0140: .short 0x140 +.L0x0150: .short 0x150 +.L0x0160: .short 0x160 +.L0x0170: .short 0x170 .Lcritical_start: - .quad __critical_start + .quad __critical_start .Lcritical_end: - .quad __critical_end + .quad __critical_end - .section .rodata, "a" + .section .rodata, "a" #define SYSCALL(esa,esame,emu) .long esame sys_call_table: #include "syscalls.S" diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index adad8863ee2f..0cf59bb7a857 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S @@ -36,508 +36,451 @@ #endif #ifndef CONFIG_IPL - .org 0 - .long 0x00080000,0x80000000+startup # Just a restart PSW + .org 0 + .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 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 - .long 0x00000000,0x00000000 # program check old psw - .long 0x00000000,0x00000000 # machine check old psw - .long 0x00000000,0x00000000 # io old psw - .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 - .long 0x000a0000,0x00000058 # external new psw - .long 0x000a0000,0x00000060 # svc new psw - .long 0x000a0000,0x00000068 # program check new psw - .long 0x000a0000,0x00000070 # machine check new psw - .long 0x00080000,0x80000000+.Lioint # io new psw - - .org 0x100 + .org 0 + .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded + .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 + .long 0x00000000,0x00000000 # program check old psw + .long 0x00000000,0x00000000 # machine check old psw + .long 0x00000000,0x00000000 # io old psw + .long 0x00000000,0x00000000 + .long 0x00000000,0x00000000 + .long 0x00000000,0x00000000 + .long 0x000a0000,0x00000058 # external new psw + .long 0x000a0000,0x00000060 # svc new psw + .long 0x000a0000,0x00000068 # program check new psw + .long 0x000a0000,0x00000070 # machine check new psw + .long 0x00080000,0x80000000+.Lioint # io new psw + + .org 0x100 # # subroutine for loading from tape -# Paramters: +# Paramters: # R1 = device number # R2 = load address -.Lloader: - st %r14,.Lldret - la %r3,.Lorbread # r3 = address of orb - la %r5,.Lirb # r5 = address of irb - st %r2,.Lccwread+4 # initialize CCW data addresses - lctl %c6,%c6,.Lcr6 - slr %r2,%r2 +.Lloader: + st %r14,.Lldret + la %r3,.Lorbread # r3 = address of orb + la %r5,.Lirb # r5 = address of irb + st %r2,.Lccwread+4 # initialize CCW data addresses + lctl %c6,%c6,.Lcr6 + slr %r2,%r2 .Lldlp: - la %r6,3 # 3 retries + la %r6,3 # 3 retries .Lssch: - ssch 0(%r3) # load chunk of IPL_BS bytes - bnz .Llderr + ssch 0(%r3) # load chunk of IPL_BS bytes + bnz .Llderr .Lw4end: - bas %r14,.Lwait4io - tm 8(%r5),0x82 # do we have a problem ? - bnz .Lrecov - slr %r7,%r7 - icm %r7,3,10(%r5) # get residual count - lcr %r7,%r7 - 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 ? - bnz .Ldone - l %r0,.Lccwread+4 # update CCW data addresses - ar %r0,%r7 - st %r0,.Lccwread+4 - b .Lldlp + bas %r14,.Lwait4io + tm 8(%r5),0x82 # do we have a problem ? + bnz .Lrecov + slr %r7,%r7 + icm %r7,3,10(%r5) # get residual count + lcr %r7,%r7 + 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 ? + bnz .Ldone + l %r0,.Lccwread+4 # update CCW data addresses + ar %r0,%r7 + st %r0,.Lccwread+4 + b .Lldlp .Ldone: - l %r14,.Lldret - br %r14 # r2 contains the total size + l %r14,.Lldret + br %r14 # r2 contains the total size .Lrecov: - bas %r14,.Lsense # do the sensing - bct %r6,.Lssch # dec. retry count & branch - b .Llderr + bas %r14,.Lsense # do the sensing + bct %r6,.Lssch # dec. retry count & branch + b .Llderr # # Sense subroutine # .Lsense: - st %r14,.Lsnsret - la %r7,.Lorbsense - ssch 0(%r7) # start sense command - bnz .Llderr - bas %r14,.Lwait4io - l %r14,.Lsnsret - tm 8(%r5),0x82 # do we have a problem ? - bnz .Llderr - br %r14 + st %r14,.Lsnsret + la %r7,.Lorbsense + ssch 0(%r7) # start sense command + bnz .Llderr + bas %r14,.Lwait4io + l %r14,.Lsnsret + tm 8(%r5),0x82 # do we have a problem ? + bnz .Llderr + br %r14 # # Wait for interrupt subroutine # .Lwait4io: - lpsw .Lwaitpsw + lpsw .Lwaitpsw .Lioint: - c %r1,0xb8 # compare subchannel number - bne .Lwait4io - tsch 0(%r5) - slr %r0,%r0 - tm 8(%r5),0x82 # do we have a problem ? - bnz .Lwtexit - tm 8(%r5),0x04 # got device end ? - bz .Lwait4io + c %r1,0xb8 # compare subchannel number + bne .Lwait4io + tsch 0(%r5) + slr %r0,%r0 + tm 8(%r5),0x82 # do we have a problem ? + bnz .Lwtexit + tm 8(%r5),0x04 # got device end ? + bz .Lwait4io .Lwtexit: - br %r14 + br %r14 .Llderr: - lpsw .Lcrash + lpsw .Lcrash - .align 8 + .align 8 .Lorbread: - .long 0x00000000,0x0080ff00,.Lccwread - .align 8 + .long 0x00000000,0x0080ff00,.Lccwread + .align 8 .Lorbsense: - .long 0x00000000,0x0080ff00,.Lccwsense - .align 8 + .long 0x00000000,0x0080ff00,.Lccwsense + .align 8 .Lccwread: - .long 0x02200000+IPL_BS,0x00000000 + .long 0x02200000+IPL_BS,0x00000000 .Lccwsense: - .long 0x04200001,0x00000000 + .long 0x04200001,0x00000000 .Lwaitpsw: - .long 0x020a0000,0x80000000+.Lioint + .long 0x020a0000,0x80000000+.Lioint -.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -.Lcr6: .long 0xff000000 - .align 8 -.Lcrash:.long 0x000a0000,0x00000000 -.Lldret:.long 0 +.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +.Lcr6: .long 0xff000000 + .align 8 +.Lcrash:.long 0x000a0000,0x00000000 +.Lldret:.long 0 .Lsnsret: .long 0 -#endif /* CONFIG_IPL_TAPE */ +#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. - .long 0x02000068,0x60000050 # (a PSW and two CCWs). - .fill 80-24,1,0x40 # bytes 24-79 are discarded !! - .long 0x020000f0,0x60000050 # The next 160 byte are loaded - .long 0x02000140,0x60000050 # to addresses 0x18-0xb7 - .long 0x02000190,0x60000050 # They form the continuation - .long 0x020001e0,0x60000050 # of the CCW program started - .long 0x02000230,0x60000050 # by ipl and load the range - .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image - .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730 - .long 0x02000320,0x60000050 # in memory. At the end of - .long 0x02000370,0x60000050 # the channel program the PSW - .long 0x020003c0,0x60000050 # at location 0 is loaded. - .long 0x02000410,0x60000050 # Initial processing starts - .long 0x02000460,0x60000050 # at 0xf0 = iplstart. - .long 0x020004b0,0x60000050 - .long 0x02000500,0x60000050 - .long 0x02000550,0x60000050 - .long 0x020005a0,0x60000050 - .long 0x020005f0,0x60000050 - .long 0x02000640,0x60000050 - .long 0x02000690,0x60000050 - .long 0x020006e0,0x20000050 - - .org 0xf0 +#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. + .long 0x02000068,0x60000050 # (a PSW and two CCWs). + .fill 80-24,1,0x40 # bytes 24-79 are discarded !! + .long 0x020000f0,0x60000050 # The next 160 byte are loaded + .long 0x02000140,0x60000050 # to addresses 0x18-0xb7 + .long 0x02000190,0x60000050 # They form the continuation + .long 0x020001e0,0x60000050 # of the CCW program started + .long 0x02000230,0x60000050 # by ipl and load the range + .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image + .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730 + .long 0x02000320,0x60000050 # in memory. At the end of + .long 0x02000370,0x60000050 # the channel program the PSW + .long 0x020003c0,0x60000050 # at location 0 is loaded. + .long 0x02000410,0x60000050 # Initial processing starts + .long 0x02000460,0x60000050 # at 0xf0 = iplstart. + .long 0x020004b0,0x60000050 + .long 0x02000500,0x60000050 + .long 0x02000550,0x60000050 + .long 0x020005a0,0x60000050 + .long 0x020005f0,0x60000050 + .long 0x02000640,0x60000050 + .long 0x02000690,0x60000050 + .long 0x020006e0,0x20000050 + + .org 0xf0 # # subroutine for loading cards from the reader # -.Lloader: - la %r3,.Lorb # r2 = address of orb into r2 - la %r5,.Lirb # r4 = address of irb - la %r6,.Lccws - la %r7,20 +.Lloader: + la %r3,.Lorb # r2 = address of orb into r2 + la %r5,.Lirb # r4 = address of irb + la %r6,.Lccws + la %r7,20 .Linit: - st %r2,4(%r6) # initialize CCW data addresses - la %r2,0x50(%r2) - la %r6,8(%r6) - bct 7,.Linit + st %r2,4(%r6) # initialize CCW data addresses + la %r2,0x50(%r2) + la %r6,8(%r6) + bct 7,.Linit - lctl %c6,%c6,.Lcr6 # set IO subclass mask - slr %r2,%r2 + lctl %c6,%c6,.Lcr6 # set IO subclass mask + slr %r2,%r2 .Lldlp: - ssch 0(%r3) # load chunk of 1600 bytes - bnz .Llderr + ssch 0(%r3) # load chunk of 1600 bytes + bnz .Llderr .Lwait4irq: - mvc 0x78(8),.Lnewpsw # set up IO interrupt psw - lpsw .Lwaitpsw + mvc 0x78(8),.Lnewpsw # set up IO interrupt psw + lpsw .Lwaitpsw .Lioint: - c %r1,0xb8 # compare subchannel number - bne .Lwait4irq - tsch 0(%r5) - - slr %r0,%r0 - ic %r0,8(%r5) # get device status - chi %r0,8 # channel end ? - be .Lcont - chi %r0,12 # channel end + device end ? - be .Lcont - - l %r0,4(%r5) - s %r0,8(%r3) # r0/8 = number of ccws executed - mhi %r0,10 # *10 = number of bytes in ccws - lh %r3,10(%r5) # get residual count - sr %r0,%r3 # #ccws*80-residual=#bytes read - ar %r2,%r0 - - br %r14 # r2 contains the total size + c %r1,0xb8 # compare subchannel number + bne .Lwait4irq + tsch 0(%r5) + + slr %r0,%r0 + ic %r0,8(%r5) # get device status + chi %r0,8 # channel end ? + be .Lcont + chi %r0,12 # channel end + device end ? + be .Lcont + + l %r0,4(%r5) + s %r0,8(%r3) # r0/8 = number of ccws executed + mhi %r0,10 # *10 = number of bytes in ccws + lh %r3,10(%r5) # get residual count + sr %r0,%r3 # #ccws*80-residual=#bytes read + ar %r2,%r0 + + br %r14 # r2 contains the total size .Lcont: - ahi %r2,0x640 # add 0x640 to total size - la %r6,.Lccws - la %r7,20 + ahi %r2,0x640 # add 0x640 to total size + la %r6,.Lccws + la %r7,20 .Lincr: - l %r0,4(%r6) # update CCW data addresses - ahi %r0,0x640 - st %r0,4(%r6) - ahi %r6,8 - bct 7,.Lincr + l %r0,4(%r6) # update CCW data addresses + ahi %r0,0x640 + st %r0,4(%r6) + ahi %r6,8 + bct 7,.Lincr - b .Lldlp + b .Lldlp .Llderr: - lpsw .Lcrash - - .align 8 -.Lorb: .long 0x00000000,0x0080ff00,.Lccws -.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 - .align 8 -.Lcrash:.long 0x000a0000,0x00000000 + lpsw .Lcrash + + .align 8 +.Lorb: .long 0x00000000,0x0080ff00,.Lccws +.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 + .align 8 +.Lcrash:.long 0x000a0000,0x00000000 .Lnewpsw: - .long 0x00080000,0x80000000+.Lioint + .long 0x00080000,0x80000000+.Lioint .Lwaitpsw: - .long 0x020a0000,0x80000000+.Lioint + .long 0x020a0000,0x80000000+.Lioint - .align 8 -.Lccws: .rept 19 - .long 0x02600050,0x00000000 - .endr - .long 0x02200050,0x00000000 -#endif /* CONFIG_IPL_VM */ + .align 8 +.Lccws: .rept 19 + .long 0x02600050,0x00000000 + .endr + .long 0x02200050,0x00000000 +#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 - l %r12,.Lparm # pointer to parameter area - st %r1,IPL_DEVICE+ARCH_OFFSET-PARMAREA(%r12) # save ipl device number + 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 + l %r12,.Lparm # pointer to parameter area + st %r1,IPL_DEVICE+ARCH_OFFSET-PARMAREA(%r12) # save ipl device number # # load parameter file from ipl device # .Lagain1: - l %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # ramdisk loc. is temp - bas %r14,.Lloader # load parameter file - ltr %r2,%r2 # got anything ? - bz .Lnopf - chi %r2,895 - bnh .Lnotrunc - la %r2,895 + l %r2,.Linitrd # ramdisk loc. is 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+ARCH_OFFSET-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 + l %r4,.Linitrd + 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 + 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 + 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 + ic %r0,0(%r2,%r3) + chi %r0,0x20 # is it a space ? + be .Lcntlp + ahi %r2,1 + b .Leolp .Lcntlp: - brct %r2,.Ldelspc + brct %r2,.Ldelspc .Leolp: - slr %r0,%r0 - stc %r0,0(%r2,%r3) # terminate buffer + slr %r0,%r0 + stc %r0,0(%r2,%r3) # terminate buffer .Lnopf: # # load ramdisk from ipl device -# +# .Lagain2: - l %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # addr of ramdisk - bas %r14,.Lloader # load ramdisk - st %r2,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r12) # store size of ramdisk - ltr %r2,%r2 - bnz .Lrdcont - st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # no ramdisk found + l %r2,.Linitrd # addr of ramdisk + st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) + bas %r14,.Lloader # load ramdisk + st %r2,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r12) # store size of rd + ltr %r2,%r2 + bnz .Lrdcont + st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # no ramdisk found .Lrdcont: - l %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) + l %r2,.Linitrd - clc 0(3,%r2),.L_hdr # skip HDRx and EOFx - bz .Lagain2 - clc 0(3,%r2),.L_eof - bz .Lagain2 + 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 - tm __LC_CPUID,0xff # running VM ? - bno .Lnoreset - la %r2,.Lreset - lhi %r3,26 - diag %r2,%r3,8 - la %r5,.Lirb - stsch 0(%r5) # check if irq is pending - tm 30(%r5),0x0f # by verifying if any of the - bnz .Lwaitforirq # activity or status control - tm 31(%r5),0xff # bits is set in the schib - bz .Lnoreset + stidp __LC_CPUID # store cpuid + tm __LC_CPUID,0xff # running VM ? + bno .Lnoreset + la %r2,.Lreset + lhi %r3,26 + diag %r2,%r3,8 + la %r5,.Lirb + stsch 0(%r5) # check if irq is pending + tm 30(%r5),0x0f # by verifying if any of the + bnz .Lwaitforirq # activity or status control + tm 31(%r5),0xff # bits is set in the schib + bz .Lnoreset .Lwaitforirq: - mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw + mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw .Lwaitrdrirq: - lpsw .Lrdrwaitpsw + lpsw .Lrdrwaitpsw .Lrdrint: - c %r1,0xb8 # compare subchannel number - bne .Lwaitrdrirq - la %r5,.Lirb - tsch 0(%r5) + c %r1,0xb8 # compare subchannel number + bne .Lwaitrdrirq + la %r5,.Lirb + tsch 0(%r5) .Lnoreset: - b .Lnoload + b .Lnoload - .align 8 + .align 8 .Lrdrnewpsw: - .long 0x00080000,0x80000000+.Lrdrint + .long 0x00080000,0x80000000+.Lrdrint .Lrdrwaitpsw: - .long 0x020a0000,0x80000000+.Lrdrint + .long 0x020a0000,0x80000000+.Lrdrint #endif # # everything loaded, go for it # .Lnoload: - l %r1,.Lstartup - br %r1 + l %r1,.Lstartup + br %r1 +.Linitrd:.long _end + 0x400000 # default address of initrd .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' */ +.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 */ +#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 + .org 0x800 + .globl start start: - stm %r0,%r15,0x07b0 # store registers - basr %r12,%r0 + stm %r0,%r15,0x07b0 # store registers + basr %r12,%r0 .base: - l %r11,.parm - l %r8,.cmd # pointer to command buffer + l %r11,.parm + l %r8,.cmd # pointer to command buffer - ltr %r9,%r9 # do we have SALIPL parameters? - bp .sk8x8 + 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 + 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 + 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 + 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 + 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) + sr %r3,%r2 + la %r3,1(%r3) .done: - l %r1,.memsize - st %r3,ARCH_OFFSET(%r1) - slr %r0,%r0 - st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11) - st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11) - j startup # continue with startup -.tbl: .long _ebcasc # translate table -.cmd: .long COMMAND_LINE # address of command line buffer -.parm: .long PARMAREA + l %r1,.memsize + st %r3,ARCH_OFFSET(%r1) + slr %r0,%r0 + st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11) + st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11) + j startup # continue with startup +.tbl: .long _ebcasc # translate table +.cmd: .long COMMAND_LINE # address of command line buffer +.parm: .long PARMAREA .memsize: .long memory_size .fourmeg: .long 0x00400000 # 4M -.pgmnw: .long 0x00080000,.pgmx +.pgmnw: .long 0x00080000,.pgmx .lowcase: - .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 + .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 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 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 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 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 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 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 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 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 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 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 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 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 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 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7 .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff -.macro GET_IPL_DEVICE -.Lget_ipl_device: - l %r1,0xb8 # get sid - sll %r1,15 # test if subchannel is enabled - srl %r1,31 - ltr %r1,%r1 - bz 2f-.LPG1(%r13) # subchannel disabled - l %r1,0xb8 - la %r5,.Lipl_schib-.LPG1(%r13) - stsch 0(%r5) # get schib of subchannel - bnz 2f-.LPG1(%r13) # schib not available - tm 5(%r5),0x01 # devno valid? - bno 2f-.LPG1(%r13) - la %r6,ipl_parameter_flags-.LPG1(%r13) - oi 3(%r6),0x01 # set flag - la %r2,ipl_devno-.LPG1(%r13) - mvc 0(2,%r2),6(%r5) # store devno - tm 4(%r5),0x80 # qdio capable device? - bno 2f-.LPG1(%r13) - oi 3(%r6),0x02 # set flag - - # copy ipl parameters - - lhi %r0,4096 - l %r2,20(%r0) # get address of parameter list - lhi %r3,IPL_PARMBLOCK_ORIGIN - st %r3,20(%r0) - lhi %r4,1 - cr %r2,%r3 # start parameters < destination ? - jl 0f - lhi %r1,1 # copy direction is upwards - j 1f -0: lhi %r1,-1 # copy direction is downwards - ar %r2,%r0 - ar %r3,%r0 - ar %r2,%r1 - ar %r3,%r1 -1: mvc 0(1,%r3),0(%r2) # finally copy ipl parameters - ar %r3,%r1 - ar %r2,%r1 - sr %r0,%r4 - jne 1b - b 2f-.LPG1(%r13) - - .align 4 -.Lipl_schib: - .rept 13 - .long 0 - .endr - - .globl ipl_parameter_flags -ipl_parameter_flags: - .long 0 - .globl ipl_devno -ipl_devno: - .word 0 -2: -.endm - #ifdef CONFIG_64BIT #include "head64.S" #else diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index a4dc61f3285e..1b952a3664e2 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -26,8 +26,8 @@ startup:basr %r13,0 # get base # .org PARMAREA .long 0,0 # IPL_DEVICE - .long 0,RAMDISK_ORIGIN # INITRD_START - .long 0,RAMDISK_SIZE # INITRD_SIZE + .long 0,0 # INITRD_START + .long 0,0 # INITRD_SIZE .org COMMAND_LINE .byte "root=/dev/ram0 ro" @@ -37,12 +37,23 @@ startup:basr %r13,0 # get base startup_continue: basr %r13,0 # get base -.LPG1: GET_IPL_DEVICE +.LPG1: mvi __LC_AR_MODE_ID,0 # set ESA flag (mode 0) lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers l %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area # move IPL device to lowcore mvc __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12) +# +# Setup stack +# + l %r15,.Linittu-.LPG1(%r13) + mvc __LC_CURRENT(4),__TI_task(%r15) + ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union+THREAD_SIZE + st %r15,__LC_KERNEL_STACK # set end of kernel stack + ahi %r15,-96 + xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain + l %r14,.Lipl_save_parameters-.LPG1(%r13) + basr %r14,%r14 # # clear bss memory # @@ -114,6 +125,10 @@ startup_continue: b .Lfchunk-.LPG1(%r13) .align 4 +.Lipl_save_parameters: + .long ipl_save_parameters +.Linittu: + .long init_thread_union .Lpmask: .byte 0 .align 8 @@ -239,6 +254,16 @@ startup_continue: oi 3(%r12),0x80 # set IDTE flag .Lchkidte: +# +# find out if the diag 0x9c is available +# + mvc __LC_PGM_NEW_PSW(8),.Lpcdiag9c-.LPG1(%r13) + stap __LC_CPUID+4 # store cpu address + lh %r1,__LC_CPUID+4 + diag %r1,0,0x9c # test diag 0x9c + oi 2(%r12),1 # set diag9c flag +.Lchkdiag9c: + lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space, # virtual and never return ... .align 8 @@ -266,6 +291,7 @@ startup_continue: .Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg .Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte +.Lpcdiag9c:.long 0x00080000,0x80000000 + .Lchkdiag9c .Lmemsize:.long memory_size .Lmchunk:.long memory_chunk .Lmflags:.long machine_flags @@ -273,7 +299,23 @@ startup_continue: .Lbss_end: .long _end .Lparmaddr: .long PARMAREA .Lsccbaddr: .long .Lsccb + + .globl ipl_schib +ipl_schib: + .rept 13 + .long 0 + .endr + + .globl ipl_flags +ipl_flags: + .long 0 + .globl ipl_devno +ipl_devno: + .word 0 + .org 0x12000 +.globl s390_readinfo_sccb +s390_readinfo_sccb: .Lsccb: .hword 0x1000 # length, one page .byte 0x00,0x00,0x00 @@ -302,16 +344,6 @@ startup_continue: .globl _stext _stext: basr %r13,0 # get base .LPG3: -# -# Setup stack -# - l %r15,.Linittu-.LPG3(%r13) - mvc __LC_CURRENT(4),__TI_task(%r15) - ahi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union+THREAD_SIZE - st %r15,__LC_KERNEL_STACK # set end of kernel stack - ahi %r15,-96 - xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain - # check control registers stctl %c0,%c15,0(%r15) oi 2(%r15),0x40 # enable sigp emergency signal @@ -330,6 +362,5 @@ _stext: basr %r13,0 # get base # .align 8 .Ldw: .long 0x000a0000,0x00000000 -.Linittu:.long init_thread_union .Lstart:.long start_kernel .Laregs:.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 9d80c5b1ef95..b30e5897cdf7 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -15,221 +15,232 @@ # this is called either by the ipl loader or directly by PSW restart # or linload or SALIPL # - .org 0x10000 -startup:basr %r13,0 # get base -.LPG0: l %r13,0f-.LPG0(%r13) - b 0(%r13) -0: .long startup_continue + .org 0x10000 +startup:basr %r13,0 # get base +.LPG0: l %r13,0f-.LPG0(%r13) + b 0(%r13) +0: .long startup_continue # # params at 10400 (setup.h) # - .org PARMAREA - .quad 0 # IPL_DEVICE - .quad RAMDISK_ORIGIN # INITRD_START - .quad RAMDISK_SIZE # INITRD_SIZE + .org PARMAREA + .quad 0 # IPL_DEVICE + .quad 0 # INITRD_START + .quad 0 # INITRD_SIZE - .org COMMAND_LINE - .byte "root=/dev/ram0 ro" - .byte 0 + .org COMMAND_LINE + .byte "root=/dev/ram0 ro" + .byte 0 - .org 0x11000 + .org 0x11000 startup_continue: - basr %r13,0 # get base -.LPG1: sll %r13,1 # remove high order bit - srl %r13,1 - GET_IPL_DEVICE - lhi %r1,1 # mode 1 = esame - slr %r0,%r0 # set cpuid to zero - sigp %r1,%r0,0x12 # switch to esame mode - sam64 # switch to 64 bit mode - lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers - lg %r12,.Lparmaddr-.LPG1(%r13)# pointer to parameter area - # move IPL device to lowcore - mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12) + basr %r13,0 # get base +.LPG1: sll %r13,1 # remove high order bit + srl %r13,1 + lhi %r1,1 # mode 1 = esame + mvi __LC_AR_MODE_ID,1 # set esame flag + slr %r0,%r0 # set cpuid to zero + sigp %r1,%r0,0x12 # switch to esame mode + sam64 # switch to 64 bit mode + lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers + lg %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area + # move IPL device to lowcore + mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12) +# +# Setup stack +# + larl %r15,init_thread_union + lg %r14,__TI_task(%r15) # cache current in lowcore + stg %r14,__LC_CURRENT + aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE + stg %r15,__LC_KERNEL_STACK # set end of kernel stack + aghi %r15,-160 + xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain + brasl %r14,ipl_save_parameters # # clear bss memory # - larl %r2,__bss_start # start of bss segment - larl %r3,_end # end of bss segment - sgr %r3,%r2 # length of bss - sgr %r4,%r4 # - sgr %r5,%r5 # set src,length and pad to zero - mvcle %r2,%r4,0 # clear mem - jo .-4 # branch back, if not finish + larl %r2,__bss_start # start of bss segment + larl %r3,_end # end of bss segment + sgr %r3,%r2 # length of bss + sgr %r4,%r4 # + sgr %r5,%r5 # set src,length and pad to zero + mvcle %r2,%r4,0 # clear mem + jo .-4 # branch back, if not finish - l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word + l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word .Lservicecall: - stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts + stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts - stctg %r0,%r0,.Lcr-.LPG1(%r13) # get cr0 - la %r1,0x200 # set bit 22 - og %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1 - stg %r1,.Lcr-.LPG1(%r13) - lctlg %r0,%r0,.Lcr-.LPG1(%r13) # load modified cr0 + stctg %r0,%r0,.Lcr-.LPG1(%r13) # get cr0 + la %r1,0x200 # set bit 22 + og %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1 + stg %r1,.Lcr-.LPG1(%r13) + lctlg %r0,%r0,.Lcr-.LPG1(%r13) # load modified cr0 - mvc __LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw - larl %r1,.Lsclph - stg %r1,__LC_EXT_NEW_PSW+8 # set handler + mvc __LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw + larl %r1,.Lsclph + stg %r1,__LC_EXT_NEW_PSW+8 # set handler - larl %r4,.Lsccb # %r4 is our index for sccb stuff - lgr %r1,%r4 # our sccb - .insn rre,0xb2200000,%r2,%r1 # service call - ipm %r1 - srl %r1,28 # get cc code - xr %r3,%r3 - chi %r1,3 - be .Lfchunk-.LPG1(%r13) # leave - chi %r1,2 - be .Lservicecall-.LPG1(%r13) - lpswe .Lwaitsclp-.LPG1(%r13) + larl %r4,.Lsccb # %r4 is our index for sccb stuff + lgr %r1,%r4 # our sccb + .insn rre,0xb2200000,%r2,%r1 # service call + ipm %r1 + srl %r1,28 # get cc code + xr %r3,%r3 + chi %r1,3 + be .Lfchunk-.LPG1(%r13) # leave + chi %r1,2 + be .Lservicecall-.LPG1(%r13) + lpswe .Lwaitsclp-.LPG1(%r13) .Lsclph: - lh %r1,.Lsccbr-.Lsccb(%r4) - chi %r1,0x10 # 0x0010 is the sucess code - je .Lprocsccb # let's process the sccb - chi %r1,0x1f0 - bne .Lfchunk-.LPG1(%r13) # unhandled error code - c %r2,.Lrcp-.LPG1(%r13) # Did we try Read SCP forced - bne .Lfchunk-.LPG1(%r13) # if no, give up - l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP - b .Lservicecall-.LPG1(%r13) + lh %r1,.Lsccbr-.Lsccb(%r4) + chi %r1,0x10 # 0x0010 is the sucess code + je .Lprocsccb # let's process the sccb + chi %r1,0x1f0 + bne .Lfchunk-.LPG1(%r13) # unhandled error code + c %r2,.Lrcp-.LPG1(%r13) # Did we try Read SCP forced + bne .Lfchunk-.LPG1(%r13) # if no, give up + l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP + b .Lservicecall-.LPG1(%r13) .Lprocsccb: - lghi %r1,0 - icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0 - jnz .Lscnd - lg %r1,.Lscpincr2-.Lsccb(%r4) # otherwise use this one + lghi %r1,0 + icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0 + jnz .Lscnd + lg %r1,.Lscpincr2-.Lsccb(%r4) # otherwise use this one .Lscnd: - xr %r3,%r3 # same logic - ic %r3,.Lscpa1-.Lsccb(%r4) - chi %r3,0x00 - jne .Lcompmem - l %r3,.Lscpa2-.Lsccb(%r4) + xr %r3,%r3 # same logic + ic %r3,.Lscpa1-.Lsccb(%r4) + chi %r3,0x00 + jne .Lcompmem + l %r3,.Lscpa2-.Lsccb(%r4) .Lcompmem: - mlgr %r2,%r1 # mem in MB on 128-bit - l %r1,.Lonemb-.LPG1(%r13) - mlgr %r2,%r1 # mem size in bytes in %r3 - b .Lfchunk-.LPG1(%r13) + mlgr %r2,%r1 # mem in MB on 128-bit + l %r1,.Lonemb-.LPG1(%r13) + mlgr %r2,%r1 # mem size in bytes in %r3 + b .Lfchunk-.LPG1(%r13) - .align 4 + .align 4 .Lpmask: - .byte 0 - .align 8 + .byte 0 + .align 8 .Lcr: - .quad 0x00 # place holder for cr0 + .quad 0x00 # place holder for cr0 .Lwaitsclp: - .quad 0x0102000180000000,.Lsclph + .quad 0x0102000180000000,.Lsclph .Lrcp: - .int 0x00120001 # Read SCP forced code + .int 0x00120001 # Read SCP forced code .Lrcp2: - .int 0x00020001 # Read SCP code + .int 0x00020001 # Read SCP code .Lonemb: - .int 0x100000 + .int 0x100000 .Lfchunk: - # set program check new psw mask - mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) + # set program check new psw mask + mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # # find memory chunks. # - lgr %r9,%r3 # end of mem - larl %r1,.Lchkmem # set program check address - stg %r1,__LC_PGM_NEW_PSW+8 - la %r1,1 # test in increments of 128KB - sllg %r1,%r1,17 - larl %r3,memory_chunk - slgr %r4,%r4 # set start of chunk to zero - slgr %r5,%r5 # set end of chunk to zero - slr %r6,%r6 # set access code to zero - la %r10,MEMORY_CHUNKS # number of chunks + lgr %r9,%r3 # end of mem + larl %r1,.Lchkmem # set program check address + stg %r1,__LC_PGM_NEW_PSW+8 + la %r1,1 # test in increments of 128KB + sllg %r1,%r1,17 + larl %r3,memory_chunk + slgr %r4,%r4 # set start of chunk to zero + slgr %r5,%r5 # set end of chunk to zero + slr %r6,%r6 # set access code to zero + la %r10,MEMORY_CHUNKS # number of chunks .Lloop: - tprot 0(%r5),0 # test protection of first byte - ipm %r7 - srl %r7,28 - clr %r6,%r7 # compare cc with last access code - je .Lsame - j .Lchkmem + tprot 0(%r5),0 # test protection of first byte + ipm %r7 + srl %r7,28 + clr %r6,%r7 # compare cc with last access code + je .Lsame + j .Lchkmem .Lsame: - algr %r5,%r1 # add 128KB to end of chunk - # no need to check here, - brc 12,.Lloop # this is the same chunk -.Lchkmem: # > 16EB or tprot got a program check - clgr %r4,%r5 # chunk size > 0? - je .Lchkloop - stg %r4,0(%r3) # store start address of chunk - lgr %r0,%r5 - slgr %r0,%r4 - stg %r0,8(%r3) # store size of chunk - st %r6,20(%r3) # store type of chunk - la %r3,24(%r3) - larl %r8,memory_size - stg %r5,0(%r8) # store memory size - ahi %r10,-1 # update chunk number + algr %r5,%r1 # add 128KB to end of chunk + # no need to check here, + brc 12,.Lloop # this is the same chunk +.Lchkmem: # > 16EB or tprot got a program check + clgr %r4,%r5 # chunk size > 0? + je .Lchkloop + stg %r4,0(%r3) # store start address of chunk + lgr %r0,%r5 + slgr %r0,%r4 + stg %r0,8(%r3) # store size of chunk + st %r6,20(%r3) # store type of chunk + la %r3,24(%r3) + larl %r8,memory_size + stg %r5,0(%r8) # store memory size + ahi %r10,-1 # update chunk number .Lchkloop: - lr %r6,%r7 # set access code to last cc + lr %r6,%r7 # set access code to last cc # we got an exception or we're starting a new # chunk , we must check if we should # still try to find valid memory (if we detected # the amount of available storage), and if we # have chunks left - lghi %r4,1 - sllg %r4,%r4,31 - clgr %r5,%r4 - je .Lhsaskip - xr %r0, %r0 - clgr %r0, %r9 # did we detect memory? - je .Ldonemem # if not, leave - chi %r10, 0 # do we have chunks left? - je .Ldonemem + lghi %r4,1 + sllg %r4,%r4,31 + clgr %r5,%r4 + je .Lhsaskip + xr %r0, %r0 + clgr %r0, %r9 # did we detect memory? + je .Ldonemem # if not, leave + chi %r10, 0 # do we have chunks left? + je .Ldonemem .Lhsaskip: - algr %r5,%r1 # add 128KB to end of chunk - lgr %r4,%r5 # potential new chunk - clgr %r5,%r9 # should we go on? - jl .Lloop -.Ldonemem: + algr %r5,%r1 # add 128KB to end of chunk + lgr %r4,%r5 # potential new chunk + clgr %r5,%r9 # should we go on? + jl .Lloop +.Ldonemem: - larl %r12,machine_flags + larl %r12,machine_flags # # find out if we are running under VM # - stidp __LC_CPUID # store cpuid - tm __LC_CPUID,0xff # running under VM ? - bno 0f-.LPG1(%r13) - oi 7(%r12),1 # set VM flag -0: lh %r0,__LC_CPUID+4 # get cpu version - chi %r0,0x7490 # running on a P/390 ? - bne 1f-.LPG1(%r13) - oi 7(%r12),4 # set P/390 flag + stidp __LC_CPUID # store cpuid + tm __LC_CPUID,0xff # running under VM ? + bno 0f-.LPG1(%r13) + oi 7(%r12),1 # set VM flag +0: lh %r0,__LC_CPUID+4 # get cpu version + chi %r0,0x7490 # running on a P/390 ? + bne 1f-.LPG1(%r13) + oi 7(%r12),4 # set P/390 flag 1: # # find out if we have the MVPG instruction # - la %r1,0f-.LPG1(%r13) # set program check address - stg %r1,__LC_PGM_NEW_PSW+8 - sgr %r0,%r0 - lghi %r1,0 - lghi %r2,0 - mvpg %r1,%r2 # test MVPG instruction - oi 7(%r12),16 # set MVPG flag + la %r1,0f-.LPG1(%r13) # set program check address + stg %r1,__LC_PGM_NEW_PSW+8 + sgr %r0,%r0 + lghi %r1,0 + lghi %r2,0 + mvpg %r1,%r2 # test MVPG instruction + oi 7(%r12),16 # set MVPG flag 0: # # find out if the diag 0x44 works in 64 bit mode # - la %r1,0f-.LPG1(%r13) # set program check address - stg %r1,__LC_PGM_NEW_PSW+8 - diag 0,0,0x44 # test diag 0x44 - oi 7(%r12),32 # set diag44 flag -0: + la %r1,0f-.LPG1(%r13) # set program check address + stg %r1,__LC_PGM_NEW_PSW+8 + diag 0,0,0x44 # test diag 0x44 + oi 7(%r12),32 # set diag44 flag +0: # # find out if we have the IDTE instruction # - la %r1,0f-.LPG1(%r13) # set program check address - stg %r1,__LC_PGM_NEW_PSW+8 + la %r1,0f-.LPG1(%r13) # set program check address + stg %r1,__LC_PGM_NEW_PSW+8 .long 0xb2b10000 # store facility list tm 0xc8,0x08 # check bit for clearing-by-ASCE bno 0f-.LPG1(%r13) @@ -239,90 +250,117 @@ startup_continue: oi 7(%r12),0x80 # set IDTE flag 0: - lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space, - # virtual and never return ... - .align 16 -.Lentry:.quad 0x0000000180000000,_stext -.Lctl: .quad 0x04b50002 # cr0: various things - .quad 0 # cr1: primary space segment table - .quad .Lduct # cr2: dispatchable unit control table - .quad 0 # cr3: instruction authorization - .quad 0 # cr4: instruction authorization - .quad 0xffffffffffffffff # cr5: primary-aste origin - .quad 0 # cr6: I/O interrupts - .quad 0 # cr7: secondary space segment table - .quad 0 # cr8: access registers translation - .quad 0 # cr9: tracing off - .quad 0 # cr10: tracing off - .quad 0 # cr11: tracing off - .quad 0 # cr12: tracing off - .quad 0 # cr13: home space segment table - .quad 0xc0000000 # cr14: machine check handling off - .quad 0 # cr15: linkage stack operations -.Lduct: .long 0,0,0,0,0,0,0,0 - .long 0,0,0,0,0,0,0,0 -.Lpcmsk:.quad 0x0000000180000000 +# +# find out if the diag 0x9c is available +# + la %r1,0f-.LPG1(%r13) # set program check address + stg %r1,__LC_PGM_NEW_PSW+8 + stap __LC_CPUID+4 # store cpu address + lh %r1,__LC_CPUID+4 + diag %r1,0,0x9c # test diag 0x9c + oi 6(%r12),1 # set diag9c flag +0: + +# +# find out if we have the MVCOS instruction +# + la %r1,0f-.LPG1(%r13) # set program check address + stg %r1,__LC_PGM_NEW_PSW+8 + .short 0xc800 # mvcos 0(%r0),0(%r0),%r0 + .short 0x0000 + .short 0x0000 +0: tm 0x8f,0x13 # special-operation exception? + bno 1f-.LPG1(%r13) # if yes, MVCOS is present + oi 6(%r12),2 # set MVCOS flag +1: + + lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space, + # virtual and never return ... + .align 16 +.Lentry:.quad 0x0000000180000000,_stext +.Lctl: .quad 0x04b50002 # cr0: various things + .quad 0 # cr1: primary space segment table + .quad .Lduct # cr2: dispatchable unit control table + .quad 0 # cr3: instruction authorization + .quad 0 # cr4: instruction authorization + .quad 0xffffffffffffffff # cr5: primary-aste origin + .quad 0 # cr6: I/O interrupts + .quad 0 # cr7: secondary space segment table + .quad 0 # cr8: access registers translation + .quad 0 # cr9: tracing off + .quad 0 # cr10: tracing off + .quad 0 # cr11: tracing off + .quad 0 # cr12: tracing off + .quad 0 # cr13: home space segment table + .quad 0xc0000000 # cr14: machine check handling off + .quad 0 # cr15: linkage stack operations +.Lduct: .long 0,0,0,0,0,0,0,0 + .long 0,0,0,0,0,0,0,0 +.Lpcmsk:.quad 0x0000000180000000 .L4malign:.quad 0xffffffffffc00000 -.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8 -.Lnop: .long 0x07000700 +.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8 +.Lnop: .long 0x07000700 .Lparmaddr: .quad PARMAREA + .globl ipl_schib +ipl_schib: + .rept 13 + .long 0 + .endr + + .globl ipl_flags +ipl_flags: + .long 0 + .globl ipl_devno +ipl_devno: + .word 0 + .org 0x12000 +.globl s390_readinfo_sccb +s390_readinfo_sccb: .Lsccb: - .hword 0x1000 # length, one page - .byte 0x00,0x00,0x00 - .byte 0x80 # variable response bit set + .hword 0x1000 # length, one page + .byte 0x00,0x00,0x00 + .byte 0x80 # variable response bit set .Lsccbr: - .hword 0x00 # response code + .hword 0x00 # response code .Lscpincr1: - .hword 0x00 + .hword 0x00 .Lscpa1: - .byte 0x00 - .fill 89,1,0 + .byte 0x00 + .fill 89,1,0 .Lscpa2: - .int 0x00 + .int 0x00 .Lscpincr2: - .quad 0x00 - .fill 3984,1,0 + .quad 0x00 + .fill 3984,1,0 .org 0x13000 #ifdef CONFIG_SHARED_KERNEL - .org 0x100000 + .org 0x100000 #endif - + # # startup-code, running in absolute addressing mode # - .globl _stext -_stext: basr %r13,0 # get base + .globl _stext +_stext: basr %r13,0 # get base .LPG3: -# -# Setup stack -# - larl %r15,init_thread_union - lg %r14,__TI_task(%r15) # cache current in lowcore - stg %r14,__LC_CURRENT - aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE - stg %r15,__LC_KERNEL_STACK # set end of kernel stack - aghi %r15,-160 - xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain - # check control registers - stctg %c0,%c15,0(%r15) - oi 6(%r15),0x40 # enable sigp emergency signal - oi 4(%r15),0x10 # switch on low address proctection - lctlg %c0,%c15,0(%r15) + stctg %c0,%c15,0(%r15) + oi 6(%r15),0x40 # enable sigp emergency signal + oi 4(%r15),0x10 # switch on low address proctection + lctlg %c0,%c15,0(%r15) -# - lam 0,15,.Laregs-.LPG3(%r13) # load access regs needed by uaccess - brasl %r14,start_kernel # go to C code + lam 0,15,.Laregs-.LPG3(%r13) # load acrs needed by uaccess + brasl %r14,start_kernel # go to C code # # We returned from start_kernel ?!? PANIK # - basr %r13,0 - lpswe .Ldw-.(%r13) # load disabled wait psw -# - .align 8 -.Ldw: .quad 0x0002000180000000,0x0000000000000000 -.Laregs: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + basr %r13,0 + lpswe .Ldw-.(%r13) # load disabled wait psw + + .align 8 +.Ldw: .quad 0x0002000180000000,0x0000000000000000 +.Laregs:.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c new file mode 100644 index 000000000000..1f5e782b3d05 --- /dev/null +++ b/arch/s390/kernel/ipl.c @@ -0,0 +1,933 @@ +/* + * arch/s390/kernel/ipl.c + * ipl/reipl/dump support for Linux on s390. + * + * Copyright (C) IBM Corp. 2005,2006 + * Author(s): Michael Holzheu <holzheu@de.ibm.com> + * Heiko Carstens <heiko.carstens@de.ibm.com> + * Volker Sameske <sameske@de.ibm.com> + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/reboot.h> +#include <asm/smp.h> +#include <asm/setup.h> +#include <asm/cpcmd.h> +#include <asm/cio.h> + +#define IPL_PARM_BLOCK_VERSION 0 + +enum ipl_type { + IPL_TYPE_NONE = 1, + IPL_TYPE_UNKNOWN = 2, + IPL_TYPE_CCW = 4, + IPL_TYPE_FCP = 8, +}; + +#define IPL_NONE_STR "none" +#define IPL_UNKNOWN_STR "unknown" +#define IPL_CCW_STR "ccw" +#define IPL_FCP_STR "fcp" + +static char *ipl_type_str(enum ipl_type type) +{ + switch (type) { + case IPL_TYPE_NONE: + return IPL_NONE_STR; + case IPL_TYPE_CCW: + return IPL_CCW_STR; + case IPL_TYPE_FCP: + return IPL_FCP_STR; + case IPL_TYPE_UNKNOWN: + default: + return IPL_UNKNOWN_STR; + } +} + +enum ipl_method { + IPL_METHOD_NONE, + IPL_METHOD_CCW_CIO, + IPL_METHOD_CCW_DIAG, + IPL_METHOD_CCW_VM, + IPL_METHOD_FCP_RO_DIAG, + IPL_METHOD_FCP_RW_DIAG, + IPL_METHOD_FCP_RO_VM, +}; + +enum shutdown_action { + SHUTDOWN_REIPL, + SHUTDOWN_DUMP, + SHUTDOWN_STOP, +}; + +#define SHUTDOWN_REIPL_STR "reipl" +#define SHUTDOWN_DUMP_STR "dump" +#define SHUTDOWN_STOP_STR "stop" + +static char *shutdown_action_str(enum shutdown_action action) +{ + switch (action) { + case SHUTDOWN_REIPL: + return SHUTDOWN_REIPL_STR; + case SHUTDOWN_DUMP: + return SHUTDOWN_DUMP_STR; + case SHUTDOWN_STOP: + return SHUTDOWN_STOP_STR; + default: + BUG(); + } +} + +enum diag308_subcode { + DIAG308_IPL = 3, + DIAG308_DUMP = 4, + DIAG308_SET = 5, + DIAG308_STORE = 6, +}; + +enum diag308_ipl_type { + DIAG308_IPL_TYPE_FCP = 0, + DIAG308_IPL_TYPE_CCW = 2, +}; + +enum diag308_opt { + DIAG308_IPL_OPT_IPL = 0x10, + DIAG308_IPL_OPT_DUMP = 0x20, +}; + +enum diag308_rc { + DIAG308_RC_OK = 1, +}; + +static int diag308_set_works = 0; + +static int reipl_capabilities = IPL_TYPE_UNKNOWN; +static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN; +static enum ipl_method reipl_method = IPL_METHOD_NONE; +static struct ipl_parameter_block *reipl_block_fcp; +static struct ipl_parameter_block *reipl_block_ccw; + +static int dump_capabilities = IPL_TYPE_NONE; +static enum ipl_type dump_type = IPL_TYPE_NONE; +static enum ipl_method dump_method = IPL_METHOD_NONE; +static struct ipl_parameter_block *dump_block_fcp; +static struct ipl_parameter_block *dump_block_ccw; + +static enum shutdown_action on_panic_action = SHUTDOWN_STOP; + +static int diag308(unsigned long subcode, void *addr) +{ + register unsigned long _addr asm("0") = (unsigned long) addr; + register unsigned long _rc asm("1") = 0; + + asm volatile( + " diag %0,%2,0x308\n" + "0:\n" + EX_TABLE(0b,0b) + : "+d" (_addr), "+d" (_rc) + : "d" (subcode) : "cc", "memory"); + return _rc; +} + +/* SYSFS */ + +#define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \ +static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \ + char *page) \ +{ \ + return sprintf(page, _format, _value); \ +} \ +static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ + __ATTR(_name, S_IRUGO, sys_##_prefix##_##_name##_show, NULL); + +#define DEFINE_IPL_ATTR_RW(_prefix, _name, _fmt_out, _fmt_in, _value) \ +static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \ + char *page) \ +{ \ + return sprintf(page, _fmt_out, \ + (unsigned long long) _value); \ +} \ +static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\ + const char *buf, size_t len) \ +{ \ + unsigned long long value; \ + if (sscanf(buf, _fmt_in, &value) != 1) \ + return -EINVAL; \ + _value = value; \ + return len; \ +} \ +static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ + __ATTR(_name,(S_IRUGO | S_IWUSR), \ + sys_##_prefix##_##_name##_show, \ + sys_##_prefix##_##_name##_store); + +static void make_attrs_ro(struct attribute **attrs) +{ + while (*attrs) { + (*attrs)->mode = S_IRUGO; + attrs++; + } +} + +/* + * ipl section + */ + +static enum ipl_type ipl_get_type(void) +{ + struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; + + if (!(ipl_flags & IPL_DEVNO_VALID)) + return IPL_TYPE_UNKNOWN; + if (!(ipl_flags & IPL_PARMBLOCK_VALID)) + return IPL_TYPE_CCW; + if (ipl->hdr.version > IPL_MAX_SUPPORTED_VERSION) + return IPL_TYPE_UNKNOWN; + if (ipl->hdr.pbt != DIAG308_IPL_TYPE_FCP) + return IPL_TYPE_UNKNOWN; + return IPL_TYPE_FCP; +} + +static ssize_t ipl_type_show(struct subsystem *subsys, char *page) +{ + return sprintf(page, "%s\n", ipl_type_str(ipl_get_type())); +} + +static struct subsys_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); + +static ssize_t sys_ipl_device_show(struct subsystem *subsys, char *page) +{ + struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; + + switch (ipl_get_type()) { + case IPL_TYPE_CCW: + return sprintf(page, "0.0.%04x\n", ipl_devno); + case IPL_TYPE_FCP: + return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno); + default: + return 0; + } +} + +static struct subsys_attribute sys_ipl_device_attr = + __ATTR(device, S_IRUGO, sys_ipl_device_show, NULL); + +static ssize_t ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off, + size_t count) +{ + unsigned int size = IPL_PARMBLOCK_SIZE; + + if (off > size) + return 0; + if (off + count > size) + count = size - off; + memcpy(buf, (void *)IPL_PARMBLOCK_START + off, count); + return count; +} + +static struct bin_attribute ipl_parameter_attr = { + .attr = { + .name = "binary_parameter", + .mode = S_IRUGO, + .owner = THIS_MODULE, + }, + .size = PAGE_SIZE, + .read = &ipl_parameter_read, +}; + +static ssize_t ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off, + size_t count) +{ + unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len; + void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data; + + if (off > size) + return 0; + if (off + count > size) + count = size - off; + memcpy(buf, scp_data + off, count); + return count; +} + +static struct bin_attribute ipl_scp_data_attr = { + .attr = { + .name = "scp_data", + .mode = S_IRUGO, + .owner = THIS_MODULE, + }, + .size = PAGE_SIZE, + .read = &ipl_scp_data_read, +}; + +/* FCP ipl device attributes */ + +DEFINE_IPL_ATTR_RO(ipl_fcp, wwpn, "0x%016llx\n", (unsigned long long) + IPL_PARMBLOCK_START->ipl_info.fcp.wwpn); +DEFINE_IPL_ATTR_RO(ipl_fcp, lun, "0x%016llx\n", (unsigned long long) + IPL_PARMBLOCK_START->ipl_info.fcp.lun); +DEFINE_IPL_ATTR_RO(ipl_fcp, bootprog, "%lld\n", (unsigned long long) + IPL_PARMBLOCK_START->ipl_info.fcp.bootprog); +DEFINE_IPL_ATTR_RO(ipl_fcp, br_lba, "%lld\n", (unsigned long long) + IPL_PARMBLOCK_START->ipl_info.fcp.br_lba); + +static struct attribute *ipl_fcp_attrs[] = { + &sys_ipl_type_attr.attr, + &sys_ipl_device_attr.attr, + &sys_ipl_fcp_wwpn_attr.attr, + &sys_ipl_fcp_lun_attr.attr, + &sys_ipl_fcp_bootprog_attr.attr, + &sys_ipl_fcp_br_lba_attr.attr, + NULL, +}; + +static struct attribute_group ipl_fcp_attr_group = { + .attrs = ipl_fcp_attrs, +}; + +/* CCW ipl device attributes */ + +static struct attribute *ipl_ccw_attrs[] = { + &sys_ipl_type_attr.attr, + &sys_ipl_device_attr.attr, + NULL, +}; + +static struct attribute_group ipl_ccw_attr_group = { + .attrs = ipl_ccw_attrs, +}; + +/* UNKNOWN ipl device attributes */ + +static struct attribute *ipl_unknown_attrs[] = { + &sys_ipl_type_attr.attr, + NULL, +}; + +static struct attribute_group ipl_unknown_attr_group = { + .attrs = ipl_unknown_attrs, +}; + +static decl_subsys(ipl, NULL, NULL); + +/* + * reipl section + */ + +/* FCP reipl device attributes */ + +DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n", + reipl_block_fcp->ipl_info.fcp.wwpn); +DEFINE_IPL_ATTR_RW(reipl_fcp, lun, "0x%016llx\n", "%016llx\n", + reipl_block_fcp->ipl_info.fcp.lun); +DEFINE_IPL_ATTR_RW(reipl_fcp, bootprog, "%lld\n", "%lld\n", + reipl_block_fcp->ipl_info.fcp.bootprog); +DEFINE_IPL_ATTR_RW(reipl_fcp, br_lba, "%lld\n", "%lld\n", + reipl_block_fcp->ipl_info.fcp.br_lba); +DEFINE_IPL_ATTR_RW(reipl_fcp, device, "0.0.%04llx\n", "0.0.%llx\n", + reipl_block_fcp->ipl_info.fcp.devno); + +static struct attribute *reipl_fcp_attrs[] = { + &sys_reipl_fcp_device_attr.attr, + &sys_reipl_fcp_wwpn_attr.attr, + &sys_reipl_fcp_lun_attr.attr, + &sys_reipl_fcp_bootprog_attr.attr, + &sys_reipl_fcp_br_lba_attr.attr, + NULL, +}; + +static struct attribute_group reipl_fcp_attr_group = { + .name = IPL_FCP_STR, + .attrs = reipl_fcp_attrs, +}; + +/* CCW reipl device attributes */ + +DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", + reipl_block_ccw->ipl_info.ccw.devno); + +static struct attribute *reipl_ccw_attrs[] = { + &sys_reipl_ccw_device_attr.attr, + NULL, +}; + +static struct attribute_group reipl_ccw_attr_group = { + .name = IPL_CCW_STR, + .attrs = reipl_ccw_attrs, +}; + +/* reipl type */ + +static int reipl_set_type(enum ipl_type type) +{ + if (!(reipl_capabilities & type)) + return -EINVAL; + + switch(type) { + case IPL_TYPE_CCW: + if (MACHINE_IS_VM) + reipl_method = IPL_METHOD_CCW_VM; + else + reipl_method = IPL_METHOD_CCW_CIO; + break; + case IPL_TYPE_FCP: + if (diag308_set_works) + reipl_method = IPL_METHOD_FCP_RW_DIAG; + else if (MACHINE_IS_VM) + reipl_method = IPL_METHOD_FCP_RO_VM; + else + reipl_method = IPL_METHOD_FCP_RO_DIAG; + break; + default: + reipl_method = IPL_METHOD_NONE; + } + reipl_type = type; + return 0; +} + +static ssize_t reipl_type_show(struct subsystem *subsys, char *page) +{ + return sprintf(page, "%s\n", ipl_type_str(reipl_type)); +} + +static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf, + size_t len) +{ + int rc = -EINVAL; + + if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0) + rc = reipl_set_type(IPL_TYPE_CCW); + else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0) + rc = reipl_set_type(IPL_TYPE_FCP); + return (rc != 0) ? rc : len; +} + +static struct subsys_attribute reipl_type_attr = + __ATTR(reipl_type, 0644, reipl_type_show, reipl_type_store); + +static decl_subsys(reipl, NULL, NULL); + +/* + * dump section + */ + +/* FCP dump device attributes */ + +DEFINE_IPL_ATTR_RW(dump_fcp, wwpn, "0x%016llx\n", "%016llx\n", + dump_block_fcp->ipl_info.fcp.wwpn); +DEFINE_IPL_ATTR_RW(dump_fcp, lun, "0x%016llx\n", "%016llx\n", + dump_block_fcp->ipl_info.fcp.lun); +DEFINE_IPL_ATTR_RW(dump_fcp, bootprog, "%lld\n", "%lld\n", + dump_block_fcp->ipl_info.fcp.bootprog); +DEFINE_IPL_ATTR_RW(dump_fcp, br_lba, "%lld\n", "%lld\n", + dump_block_fcp->ipl_info.fcp.br_lba); +DEFINE_IPL_ATTR_RW(dump_fcp, device, "0.0.%04llx\n", "0.0.%llx\n", + dump_block_fcp->ipl_info.fcp.devno); + +static struct attribute *dump_fcp_attrs[] = { + &sys_dump_fcp_device_attr.attr, + &sys_dump_fcp_wwpn_attr.attr, + &sys_dump_fcp_lun_attr.attr, + &sys_dump_fcp_bootprog_attr.attr, + &sys_dump_fcp_br_lba_attr.attr, + NULL, +}; + +static struct attribute_group dump_fcp_attr_group = { + .name = IPL_FCP_STR, + .attrs = dump_fcp_attrs, +}; + +/* CCW dump device attributes */ + +DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", + dump_block_ccw->ipl_info.ccw.devno); + +static struct attribute *dump_ccw_attrs[] = { + &sys_dump_ccw_device_attr.attr, + NULL, +}; + +static struct attribute_group dump_ccw_attr_group = { + .name = IPL_CCW_STR, + .attrs = dump_ccw_attrs, +}; + +/* dump type */ + +static int dump_set_type(enum ipl_type type) +{ + if (!(dump_capabilities & type)) + return -EINVAL; + switch(type) { + case IPL_TYPE_CCW: + if (MACHINE_IS_VM) + dump_method = IPL_METHOD_CCW_VM; + else + dump_method = IPL_METHOD_CCW_CIO; + break; + case IPL_TYPE_FCP: + dump_method = IPL_METHOD_FCP_RW_DIAG; + break; + default: + dump_method = IPL_METHOD_NONE; + } + dump_type = type; + return 0; +} + +static ssize_t dump_type_show(struct subsystem *subsys, char *page) +{ + return sprintf(page, "%s\n", ipl_type_str(dump_type)); +} + +static ssize_t dump_type_store(struct subsystem *subsys, const char *buf, + size_t len) +{ + int rc = -EINVAL; + + if (strncmp(buf, IPL_NONE_STR, strlen(IPL_NONE_STR)) == 0) + rc = dump_set_type(IPL_TYPE_NONE); + else if (strncmp(buf, IPL_CCW_STR, strlen(IPL_CCW_STR)) == 0) + rc = dump_set_type(IPL_TYPE_CCW); + else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0) + rc = dump_set_type(IPL_TYPE_FCP); + return (rc != 0) ? rc : len; +} + +static struct subsys_attribute dump_type_attr = + __ATTR(dump_type, 0644, dump_type_show, dump_type_store); + +static decl_subsys(dump, NULL, NULL); + +#ifdef CONFIG_SMP +static void dump_smp_stop_all(void) +{ + int cpu; + preempt_disable(); + for_each_online_cpu(cpu) { + if (cpu == smp_processor_id()) + continue; + while (signal_processor(cpu, sigp_stop) == sigp_busy) + udelay(10); + } + preempt_enable(); +} +#else +#define dump_smp_stop_all() do { } while (0) +#endif + +/* + * Shutdown actions section + */ + +static decl_subsys(shutdown_actions, NULL, NULL); + +/* on panic */ + +static ssize_t on_panic_show(struct subsystem *subsys, char *page) +{ + return sprintf(page, "%s\n", shutdown_action_str(on_panic_action)); +} + +static ssize_t on_panic_store(struct subsystem *subsys, const char *buf, + size_t len) +{ + if (strncmp(buf, SHUTDOWN_REIPL_STR, strlen(SHUTDOWN_REIPL_STR)) == 0) + on_panic_action = SHUTDOWN_REIPL; + else if (strncmp(buf, SHUTDOWN_DUMP_STR, + strlen(SHUTDOWN_DUMP_STR)) == 0) + on_panic_action = SHUTDOWN_DUMP; + else if (strncmp(buf, SHUTDOWN_STOP_STR, + strlen(SHUTDOWN_STOP_STR)) == 0) + on_panic_action = SHUTDOWN_STOP; + else + return -EINVAL; + + return len; +} + +static struct subsys_attribute on_panic_attr = + __ATTR(on_panic, 0644, on_panic_show, on_panic_store); + +static void print_fcp_block(struct ipl_parameter_block *fcp_block) +{ + printk(KERN_EMERG "wwpn: %016llx\n", + (unsigned long long)fcp_block->ipl_info.fcp.wwpn); + printk(KERN_EMERG "lun: %016llx\n", + (unsigned long long)fcp_block->ipl_info.fcp.lun); + printk(KERN_EMERG "bootprog: %lld\n", + (unsigned long long)fcp_block->ipl_info.fcp.bootprog); + printk(KERN_EMERG "br_lba: %lld\n", + (unsigned long long)fcp_block->ipl_info.fcp.br_lba); + printk(KERN_EMERG "device: %llx\n", + (unsigned long long)fcp_block->ipl_info.fcp.devno); + printk(KERN_EMERG "opt: %x\n", fcp_block->ipl_info.fcp.opt); +} + +void do_reipl(void) +{ + struct ccw_dev_id devid; + static char buf[100]; + + switch (reipl_type) { + case IPL_TYPE_CCW: + printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n", + reipl_block_ccw->ipl_info.ccw.devno); + break; + case IPL_TYPE_FCP: + printk(KERN_EMERG "reboot on fcp device:\n"); + print_fcp_block(reipl_block_fcp); + break; + default: + break; + } + + switch (reipl_method) { + case IPL_METHOD_CCW_CIO: + devid.devno = reipl_block_ccw->ipl_info.ccw.devno; + devid.ssid = 0; + reipl_ccw_dev(&devid); + break; + case IPL_METHOD_CCW_VM: + sprintf(buf, "IPL %X", reipl_block_ccw->ipl_info.ccw.devno); + cpcmd(buf, NULL, 0, NULL); + break; + case IPL_METHOD_CCW_DIAG: + diag308(DIAG308_SET, reipl_block_ccw); + diag308(DIAG308_IPL, NULL); + break; + case IPL_METHOD_FCP_RW_DIAG: + diag308(DIAG308_SET, reipl_block_fcp); + diag308(DIAG308_IPL, NULL); + break; + case IPL_METHOD_FCP_RO_DIAG: + diag308(DIAG308_IPL, NULL); + break; + case IPL_METHOD_FCP_RO_VM: + cpcmd("IPL", NULL, 0, NULL); + break; + case IPL_METHOD_NONE: + default: + if (MACHINE_IS_VM) + cpcmd("IPL", NULL, 0, NULL); + diag308(DIAG308_IPL, NULL); + break; + } + panic("reipl failed!\n"); +} + +static void do_dump(void) +{ + struct ccw_dev_id devid; + static char buf[100]; + + switch (dump_type) { + case IPL_TYPE_CCW: + printk(KERN_EMERG "Automatic dump on ccw device: 0.0.%04x\n", + dump_block_ccw->ipl_info.ccw.devno); + break; + case IPL_TYPE_FCP: + printk(KERN_EMERG "Automatic dump on fcp device:\n"); + print_fcp_block(dump_block_fcp); + break; + default: + return; + } + + switch (dump_method) { + case IPL_METHOD_CCW_CIO: + dump_smp_stop_all(); + devid.devno = dump_block_ccw->ipl_info.ccw.devno; + devid.ssid = 0; + reipl_ccw_dev(&devid); + break; + case IPL_METHOD_CCW_VM: + dump_smp_stop_all(); + sprintf(buf, "STORE STATUS"); + cpcmd(buf, NULL, 0, NULL); + sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); + cpcmd(buf, NULL, 0, NULL); + break; + case IPL_METHOD_CCW_DIAG: + diag308(DIAG308_SET, dump_block_ccw); + diag308(DIAG308_DUMP, NULL); + break; + case IPL_METHOD_FCP_RW_DIAG: + diag308(DIAG308_SET, dump_block_fcp); + diag308(DIAG308_DUMP, NULL); + break; + case IPL_METHOD_NONE: + default: + return; + } + printk(KERN_EMERG "Dump failed!\n"); +} + +/* init functions */ + +static int __init ipl_register_fcp_files(void) +{ + int rc; + + rc = sysfs_create_group(&ipl_subsys.kset.kobj, + &ipl_fcp_attr_group); + if (rc) + goto out; + rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj, + &ipl_parameter_attr); + if (rc) + goto out_ipl_parm; + rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj, + &ipl_scp_data_attr); + if (!rc) + goto out; + + sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr); + +out_ipl_parm: + sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group); +out: + return rc; +} + +static int __init ipl_init(void) +{ + int rc; + + rc = firmware_register(&ipl_subsys); + if (rc) + return rc; + switch (ipl_get_type()) { + case IPL_TYPE_CCW: + rc = sysfs_create_group(&ipl_subsys.kset.kobj, + &ipl_ccw_attr_group); + break; + case IPL_TYPE_FCP: + rc = ipl_register_fcp_files(); + break; + default: + rc = sysfs_create_group(&ipl_subsys.kset.kobj, + &ipl_unknown_attr_group); + break; + } + if (rc) + firmware_unregister(&ipl_subsys); + return rc; +} + +static void __init reipl_probe(void) +{ + void *buffer; + + buffer = (void *) get_zeroed_page(GFP_KERNEL); + if (!buffer) + return; + if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK) + diag308_set_works = 1; + free_page((unsigned long)buffer); +} + +static int __init reipl_ccw_init(void) +{ + int rc; + + reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); + if (!reipl_block_ccw) + return -ENOMEM; + rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_ccw_attr_group); + if (rc) { + free_page((unsigned long)reipl_block_ccw); + return rc; + } + reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN; + reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; + reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw); + reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; + if (ipl_get_type() == IPL_TYPE_CCW) + reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; + reipl_capabilities |= IPL_TYPE_CCW; + return 0; +} + +static int __init reipl_fcp_init(void) +{ + int rc; + + if ((!diag308_set_works) && (ipl_get_type() != IPL_TYPE_FCP)) + return 0; + if ((!diag308_set_works) && (ipl_get_type() == IPL_TYPE_FCP)) + make_attrs_ro(reipl_fcp_attrs); + + reipl_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); + if (!reipl_block_fcp) + return -ENOMEM; + rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_fcp_attr_group); + if (rc) { + free_page((unsigned long)reipl_block_fcp); + return rc; + } + if (ipl_get_type() == IPL_TYPE_FCP) { + memcpy(reipl_block_fcp, IPL_PARMBLOCK_START, PAGE_SIZE); + } else { + reipl_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN; + reipl_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION; + reipl_block_fcp->hdr.blk0_len = + sizeof(reipl_block_fcp->ipl_info.fcp); + reipl_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP; + reipl_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_IPL; + } + reipl_capabilities |= IPL_TYPE_FCP; + return 0; +} + +static int __init reipl_init(void) +{ + int rc; + + rc = firmware_register(&reipl_subsys); + if (rc) + return rc; + rc = subsys_create_file(&reipl_subsys, &reipl_type_attr); + if (rc) { + firmware_unregister(&reipl_subsys); + return rc; + } + rc = reipl_ccw_init(); + if (rc) + return rc; + rc = reipl_fcp_init(); + if (rc) + return rc; + rc = reipl_set_type(ipl_get_type()); + if (rc) + return rc; + return 0; +} + +static int __init dump_ccw_init(void) +{ + int rc; + + dump_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); + if (!dump_block_ccw) + return -ENOMEM; + rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_ccw_attr_group); + if (rc) { + free_page((unsigned long)dump_block_ccw); + return rc; + } + dump_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN; + dump_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; + dump_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw); + dump_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; + dump_capabilities |= IPL_TYPE_CCW; + return 0; +} + +extern char s390_readinfo_sccb[]; + +static int __init dump_fcp_init(void) +{ + int rc; + + if(!(s390_readinfo_sccb[91] & 0x2)) + return 0; /* LDIPL DUMP is not installed */ + if (!diag308_set_works) + return 0; + dump_block_fcp = (void *) get_zeroed_page(GFP_KERNEL); + if (!dump_block_fcp) + return -ENOMEM; + rc = sysfs_create_group(&dump_subsys.kset.kobj, &dump_fcp_attr_group); + if (rc) { + free_page((unsigned long)dump_block_fcp); + return rc; + } + dump_block_fcp->hdr.len = IPL_PARM_BLK_FCP_LEN; + dump_block_fcp->hdr.version = IPL_PARM_BLOCK_VERSION; + dump_block_fcp->hdr.blk0_len = sizeof(dump_block_fcp->ipl_info.fcp); + dump_block_fcp->hdr.pbt = DIAG308_IPL_TYPE_FCP; + dump_block_fcp->ipl_info.fcp.opt = DIAG308_IPL_OPT_DUMP; + dump_capabilities |= IPL_TYPE_FCP; + return 0; +} + +#define SHUTDOWN_ON_PANIC_PRIO 0 + +static int shutdown_on_panic_notify(struct notifier_block *self, + unsigned long event, void *data) +{ + if (on_panic_action == SHUTDOWN_DUMP) + do_dump(); + else if (on_panic_action == SHUTDOWN_REIPL) + do_reipl(); + return NOTIFY_OK; +} + +static struct notifier_block shutdown_on_panic_nb = { + .notifier_call = shutdown_on_panic_notify, + .priority = SHUTDOWN_ON_PANIC_PRIO +}; + +static int __init dump_init(void) +{ + int rc; + + rc = firmware_register(&dump_subsys); + if (rc) + return rc; + rc = subsys_create_file(&dump_subsys, &dump_type_attr); + if (rc) { + firmware_unregister(&dump_subsys); + return rc; + } + rc = dump_ccw_init(); + if (rc) + return rc; + rc = dump_fcp_init(); + if (rc) + return rc; + dump_set_type(IPL_TYPE_NONE); + return 0; +} + +static int __init shutdown_actions_init(void) +{ + int rc; + + rc = firmware_register(&shutdown_actions_subsys); + if (rc) + return rc; + rc = subsys_create_file(&shutdown_actions_subsys, &on_panic_attr); + if (rc) { + firmware_unregister(&shutdown_actions_subsys); + return rc; + } + atomic_notifier_chain_register(&panic_notifier_list, + &shutdown_on_panic_nb); + return 0; +} + +static int __init s390_ipl_init(void) +{ + int rc; + + reipl_probe(); + rc = ipl_init(); + if (rc) + return rc; + rc = reipl_init(); + if (rc) + return rc; + rc = dump_init(); + if (rc) + return rc; + rc = shutdown_actions_init(); + if (rc) + return rc; + return 0; +} + +__initcall(s390_ipl_init); diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c new file mode 100644 index 000000000000..ca28fb0b3790 --- /dev/null +++ b/arch/s390/kernel/kprobes.c @@ -0,0 +1,657 @@ +/* + * Kernel Probes (KProbes) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) IBM Corporation, 2002, 2006 + * + * s390 port, used ppc64 as template. Mike Grundy <grundym@us.ibm.com> + */ + +#include <linux/config.h> +#include <linux/kprobes.h> +#include <linux/ptrace.h> +#include <linux/preempt.h> +#include <linux/stop_machine.h> +#include <asm/cacheflush.h> +#include <asm/kdebug.h> +#include <asm/sections.h> +#include <asm/uaccess.h> +#include <linux/module.h> + +DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; +DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); + +int __kprobes arch_prepare_kprobe(struct kprobe *p) +{ + /* Make sure the probe isn't going on a difficult instruction */ + if (is_prohibited_opcode((kprobe_opcode_t *) p->addr)) + return -EINVAL; + + if ((unsigned long)p->addr & 0x01) { + printk("Attempt to register kprobe at an unaligned address\n"); + return -EINVAL; + } + + /* Use the get_insn_slot() facility for correctness */ + if (!(p->ainsn.insn = get_insn_slot())) + return -ENOMEM; + + memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); + + get_instruction_type(&p->ainsn); + p->opcode = *p->addr; + return 0; +} + +int __kprobes is_prohibited_opcode(kprobe_opcode_t *instruction) +{ + switch (*(__u8 *) instruction) { + case 0x0c: /* bassm */ + case 0x0b: /* bsm */ + case 0x83: /* diag */ + case 0x44: /* ex */ + return -EINVAL; + } + switch (*(__u16 *) instruction) { + case 0x0101: /* pr */ + case 0xb25a: /* bsa */ + case 0xb240: /* bakr */ + case 0xb258: /* bsg */ + case 0xb218: /* pc */ + case 0xb228: /* pt */ + return -EINVAL; + } + return 0; +} + +void __kprobes get_instruction_type(struct arch_specific_insn *ainsn) +{ + /* default fixup method */ + ainsn->fixup = FIXUP_PSW_NORMAL; + + /* save r1 operand */ + ainsn->reg = (*ainsn->insn & 0xf0) >> 4; + + /* save the instruction length (pop 5-5) in bytes */ + switch (*(__u8 *) (ainsn->insn) >> 4) { + case 0: + ainsn->ilen = 2; + break; + case 1: + case 2: + ainsn->ilen = 4; + break; + case 3: + ainsn->ilen = 6; + break; + } + + switch (*(__u8 *) ainsn->insn) { + case 0x05: /* balr */ + case 0x0d: /* basr */ + ainsn->fixup = FIXUP_RETURN_REGISTER; + /* if r2 = 0, no branch will be taken */ + if ((*ainsn->insn & 0x0f) == 0) + ainsn->fixup |= FIXUP_BRANCH_NOT_TAKEN; + break; + case 0x06: /* bctr */ + case 0x07: /* bcr */ + ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN; + break; + case 0x45: /* bal */ + case 0x4d: /* bas */ + ainsn->fixup = FIXUP_RETURN_REGISTER; + break; + case 0x47: /* bc */ + case 0x46: /* bct */ + case 0x86: /* bxh */ + case 0x87: /* bxle */ + ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN; + break; + case 0x82: /* lpsw */ + ainsn->fixup = FIXUP_NOT_REQUIRED; + break; + case 0xb2: /* lpswe */ + if (*(((__u8 *) ainsn->insn) + 1) == 0xb2) { + ainsn->fixup = FIXUP_NOT_REQUIRED; + } + break; + case 0xa7: /* bras */ + if ((*ainsn->insn & 0x0f) == 0x05) { + ainsn->fixup |= FIXUP_RETURN_REGISTER; + } + break; + case 0xc0: + if ((*ainsn->insn & 0x0f) == 0x00 /* larl */ + || (*ainsn->insn & 0x0f) == 0x05) /* brasl */ + ainsn->fixup |= FIXUP_RETURN_REGISTER; + break; + case 0xeb: + if (*(((__u8 *) ainsn->insn) + 5 ) == 0x44 || /* bxhg */ + *(((__u8 *) ainsn->insn) + 5) == 0x45) {/* bxleg */ + ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN; + } + break; + case 0xe3: /* bctg */ + if (*(((__u8 *) ainsn->insn) + 5) == 0x46) { + ainsn->fixup = FIXUP_BRANCH_NOT_TAKEN; + } + break; + } +} + +static int __kprobes swap_instruction(void *aref) +{ + struct ins_replace_args *args = aref; + int err = -EFAULT; + + asm volatile( + "0: mvc 0(2,%2),0(%3)\n" + "1: la %0,0\n" + "2:\n" + EX_TABLE(0b,2b) + : "+d" (err), "=m" (*args->ptr) + : "a" (args->ptr), "a" (&args->new), "m" (args->new)); + return err; +} + +void __kprobes arch_arm_kprobe(struct kprobe *p) +{ + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + unsigned long status = kcb->kprobe_status; + struct ins_replace_args args; + + args.ptr = p->addr; + args.old = p->opcode; + args.new = BREAKPOINT_INSTRUCTION; + + kcb->kprobe_status = KPROBE_SWAP_INST; + stop_machine_run(swap_instruction, &args, NR_CPUS); + kcb->kprobe_status = status; +} + +void __kprobes arch_disarm_kprobe(struct kprobe *p) +{ + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + unsigned long status = kcb->kprobe_status; + struct ins_replace_args args; + + args.ptr = p->addr; + args.old = BREAKPOINT_INSTRUCTION; + args.new = p->opcode; + + kcb->kprobe_status = KPROBE_SWAP_INST; + stop_machine_run(swap_instruction, &args, NR_CPUS); + kcb->kprobe_status = status; +} + +void __kprobes arch_remove_kprobe(struct kprobe *p) +{ + mutex_lock(&kprobe_mutex); + free_insn_slot(p->ainsn.insn); + mutex_unlock(&kprobe_mutex); +} + +static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) +{ + per_cr_bits kprobe_per_regs[1]; + + memset(kprobe_per_regs, 0, sizeof(per_cr_bits)); + regs->psw.addr = (unsigned long)p->ainsn.insn | PSW_ADDR_AMODE; + + /* Set up the per control reg info, will pass to lctl */ + kprobe_per_regs[0].em_instruction_fetch = 1; + kprobe_per_regs[0].starting_addr = (unsigned long)p->ainsn.insn; + kprobe_per_regs[0].ending_addr = (unsigned long)p->ainsn.insn + 1; + + /* Set the PER control regs, turns on single step for this address */ + __ctl_load(kprobe_per_regs, 9, 11); + regs->psw.mask |= PSW_MASK_PER; + regs->psw.mask &= ~(PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK); +} + +static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) +{ + kcb->prev_kprobe.kp = kprobe_running(); + kcb->prev_kprobe.status = kcb->kprobe_status; + kcb->prev_kprobe.kprobe_saved_imask = kcb->kprobe_saved_imask; + memcpy(kcb->prev_kprobe.kprobe_saved_ctl, kcb->kprobe_saved_ctl, + sizeof(kcb->kprobe_saved_ctl)); +} + +static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) +{ + __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp; + kcb->kprobe_status = kcb->prev_kprobe.status; + kcb->kprobe_saved_imask = kcb->prev_kprobe.kprobe_saved_imask; + memcpy(kcb->kprobe_saved_ctl, kcb->prev_kprobe.kprobe_saved_ctl, + sizeof(kcb->kprobe_saved_ctl)); +} + +static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, + struct kprobe_ctlblk *kcb) +{ + __get_cpu_var(current_kprobe) = p; + /* Save the interrupt and per flags */ + kcb->kprobe_saved_imask = regs->psw.mask & + (PSW_MASK_PER | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK); + /* Save the control regs that govern PER */ + __ctl_store(kcb->kprobe_saved_ctl, 9, 11); +} + +/* Called with kretprobe_lock held */ +void __kprobes arch_prepare_kretprobe(struct kretprobe *rp, + struct pt_regs *regs) +{ + struct kretprobe_instance *ri; + + if ((ri = get_free_rp_inst(rp)) != NULL) { + ri->rp = rp; + ri->task = current; + ri->ret_addr = (kprobe_opcode_t *) regs->gprs[14]; + + /* Replace the return addr with trampoline addr */ + regs->gprs[14] = (unsigned long)&kretprobe_trampoline; + + add_rp_inst(ri); + } else { + rp->nmissed++; + } +} + +static int __kprobes kprobe_handler(struct pt_regs *regs) +{ + struct kprobe *p; + int ret = 0; + unsigned long *addr = (unsigned long *) + ((regs->psw.addr & PSW_ADDR_INSN) - 2); + struct kprobe_ctlblk *kcb; + + /* + * We don't want to be preempted for the entire + * duration of kprobe processing + */ + preempt_disable(); + kcb = get_kprobe_ctlblk(); + + /* Check we're not actually recursing */ + if (kprobe_running()) { + p = get_kprobe(addr); + if (p) { + if (kcb->kprobe_status == KPROBE_HIT_SS && + *p->ainsn.insn == BREAKPOINT_INSTRUCTION) { + regs->psw.mask &= ~PSW_MASK_PER; + regs->psw.mask |= kcb->kprobe_saved_imask; + goto no_kprobe; + } + /* We have reentered the kprobe_handler(), since + * another probe was hit while within the handler. + * We here save the original kprobes variables and + * just single step on the instruction of the new probe + * without calling any user handlers. + */ + save_previous_kprobe(kcb); + set_current_kprobe(p, regs, kcb); + kprobes_inc_nmissed_count(p); + prepare_singlestep(p, regs); + kcb->kprobe_status = KPROBE_REENTER; + return 1; + } else { + p = __get_cpu_var(current_kprobe); + if (p->break_handler && p->break_handler(p, regs)) { + goto ss_probe; + } + } + goto no_kprobe; + } + + p = get_kprobe(addr); + if (!p) { + if (*addr != BREAKPOINT_INSTRUCTION) { + /* + * The breakpoint instruction was removed right + * after we hit it. Another cpu has removed + * either a probepoint or a debugger breakpoint + * at this address. In either case, no further + * handling of this interrupt is appropriate. + * + */ + ret = 1; + } + /* Not one of ours: let kernel handle it */ + goto no_kprobe; + } + + kcb->kprobe_status = KPROBE_HIT_ACTIVE; + set_current_kprobe(p, regs, kcb); + if (p->pre_handler && p->pre_handler(p, regs)) + /* handler has already set things up, so skip ss setup */ + return 1; + +ss_probe: + prepare_singlestep(p, regs); + kcb->kprobe_status = KPROBE_HIT_SS; + return 1; + +no_kprobe: + preempt_enable_no_resched(); + return ret; +} + +/* + * Function return probe trampoline: + * - init_kprobes() establishes a probepoint here + * - When the probed function returns, this probe + * causes the handlers to fire + */ +void __kprobes kretprobe_trampoline_holder(void) +{ + asm volatile(".global kretprobe_trampoline\n" + "kretprobe_trampoline: bcr 0,0\n"); +} + +/* + * Called when the probe at kretprobe trampoline is hit + */ +int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) +{ + struct kretprobe_instance *ri = NULL; + struct hlist_head *head; + struct hlist_node *node, *tmp; + unsigned long flags, orig_ret_address = 0; + unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; + + spin_lock_irqsave(&kretprobe_lock, flags); + head = kretprobe_inst_table_head(current); + + /* + * It is possible to have multiple instances associated with a given + * task either because an multiple functions in the call path + * have a return probe installed on them, and/or more then one return + * return probe was registered for a target function. + * + * We can handle this because: + * - instances are always inserted at the head of the list + * - when multiple return probes are registered for the same + * function, the first instance's ret_addr will point to the + * real return address, and all the rest will point to + * kretprobe_trampoline + */ + hlist_for_each_entry_safe(ri, node, tmp, head, hlist) { + if (ri->task != current) + /* another task is sharing our hash bucket */ + continue; + + if (ri->rp && ri->rp->handler) + ri->rp->handler(ri, regs); + + orig_ret_address = (unsigned long)ri->ret_addr; + recycle_rp_inst(ri); + + if (orig_ret_address != trampoline_address) { + /* + * This is the real return address. Any other + * instances associated with this task are for + * other calls deeper on the call stack + */ + break; + } + } + BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address)); + regs->psw.addr = orig_ret_address | PSW_ADDR_AMODE; + + reset_current_kprobe(); + spin_unlock_irqrestore(&kretprobe_lock, flags); + preempt_enable_no_resched(); + + /* + * By returning a non-zero value, we are telling + * kprobe_handler() that we don't want the post_handler + * to run (and have re-enabled preemption) + */ + return 1; +} + +/* + * Called after single-stepping. p->addr is the address of the + * instruction whose first byte has been replaced by the "breakpoint" + * instruction. To avoid the SMP problems that can occur when we + * temporarily put back the original opcode to single-step, we + * single-stepped a copy of the instruction. The address of this + * copy is p->ainsn.insn. + */ +static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) +{ + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + regs->psw.addr &= PSW_ADDR_INSN; + + if (p->ainsn.fixup & FIXUP_PSW_NORMAL) + regs->psw.addr = (unsigned long)p->addr + + ((unsigned long)regs->psw.addr - + (unsigned long)p->ainsn.insn); + + if (p->ainsn.fixup & FIXUP_BRANCH_NOT_TAKEN) + if ((unsigned long)regs->psw.addr - + (unsigned long)p->ainsn.insn == p->ainsn.ilen) + regs->psw.addr = (unsigned long)p->addr + p->ainsn.ilen; + + if (p->ainsn.fixup & FIXUP_RETURN_REGISTER) + regs->gprs[p->ainsn.reg] = ((unsigned long)p->addr + + (regs->gprs[p->ainsn.reg] - + (unsigned long)p->ainsn.insn)) + | PSW_ADDR_AMODE; + + regs->psw.addr |= PSW_ADDR_AMODE; + /* turn off PER mode */ + regs->psw.mask &= ~PSW_MASK_PER; + /* Restore the original per control regs */ + __ctl_load(kcb->kprobe_saved_ctl, 9, 11); + regs->psw.mask |= kcb->kprobe_saved_imask; +} + +static int __kprobes post_kprobe_handler(struct pt_regs *regs) +{ + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + if (!cur) + return 0; + + if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { + kcb->kprobe_status = KPROBE_HIT_SSDONE; + cur->post_handler(cur, regs, 0); + } + + resume_execution(cur, regs); + + /*Restore back the original saved kprobes variables and continue. */ + if (kcb->kprobe_status == KPROBE_REENTER) { + restore_previous_kprobe(kcb); + goto out; + } + reset_current_kprobe(); +out: + preempt_enable_no_resched(); + + /* + * if somebody else is singlestepping across a probe point, psw mask + * will have PER set, in which case, continue the remaining processing + * of do_single_step, as if this is not a probe hit. + */ + if (regs->psw.mask & PSW_MASK_PER) { + return 0; + } + + return 1; +} + +static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) +{ + struct kprobe *cur = kprobe_running(); + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + const struct exception_table_entry *entry; + + switch(kcb->kprobe_status) { + case KPROBE_SWAP_INST: + /* We are here because the instruction replacement failed */ + return 0; + case KPROBE_HIT_SS: + case KPROBE_REENTER: + /* + * We are here because the instruction being single + * stepped caused a page fault. We reset the current + * kprobe and the nip points back to the probe address + * and allow the page fault handler to continue as a + * normal page fault. + */ + regs->psw.addr = (unsigned long)cur->addr | PSW_ADDR_AMODE; + regs->psw.mask &= ~PSW_MASK_PER; + regs->psw.mask |= kcb->kprobe_saved_imask; + if (kcb->kprobe_status == KPROBE_REENTER) + restore_previous_kprobe(kcb); + else + reset_current_kprobe(); + preempt_enable_no_resched(); + break; + case KPROBE_HIT_ACTIVE: + case KPROBE_HIT_SSDONE: + /* + * We increment the nmissed count for accounting, + * we can also use npre/npostfault count for accouting + * these specific fault cases. + */ + kprobes_inc_nmissed_count(cur); + + /* + * We come here because instructions in the pre/post + * handler caused the page_fault, this could happen + * if handler tries to access user space by + * copy_from_user(), get_user() etc. Let the + * user-specified handler try to fix it first. + */ + if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) + return 1; + + /* + * In case the user-specified fault handler returned + * zero, try to fix up. + */ + entry = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN); + if (entry) { + regs->psw.addr = entry->fixup | PSW_ADDR_AMODE; + return 1; + } + + /* + * fixup_exception() could not handle it, + * Let do_page_fault() fix it. + */ + break; + default: + break; + } + return 0; +} + +/* + * Wrapper routine to for handling exceptions. + */ +int __kprobes kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + struct die_args *args = (struct die_args *)data; + int ret = NOTIFY_DONE; + + switch (val) { + case DIE_BPT: + if (kprobe_handler(args->regs)) + ret = NOTIFY_STOP; + break; + case DIE_SSTEP: + if (post_kprobe_handler(args->regs)) + ret = NOTIFY_STOP; + break; + case DIE_TRAP: + case DIE_PAGE_FAULT: + /* kprobe_running() needs smp_processor_id() */ + preempt_disable(); + if (kprobe_running() && + kprobe_fault_handler(args->regs, args->trapnr)) + ret = NOTIFY_STOP; + preempt_enable(); + break; + default: + break; + } + return ret; +} + +int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) +{ + struct jprobe *jp = container_of(p, struct jprobe, kp); + unsigned long addr; + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + + memcpy(&kcb->jprobe_saved_regs, regs, sizeof(struct pt_regs)); + + /* setup return addr to the jprobe handler routine */ + regs->psw.addr = (unsigned long)(jp->entry) | PSW_ADDR_AMODE; + + /* r14 is the function return address */ + kcb->jprobe_saved_r14 = (unsigned long)regs->gprs[14]; + /* r15 is the stack pointer */ + kcb->jprobe_saved_r15 = (unsigned long)regs->gprs[15]; + addr = (unsigned long)kcb->jprobe_saved_r15; + + memcpy(kcb->jprobes_stack, (kprobe_opcode_t *) addr, + MIN_STACK_SIZE(addr)); + return 1; +} + +void __kprobes jprobe_return(void) +{ + asm volatile(".word 0x0002"); +} + +void __kprobes jprobe_return_end(void) +{ + asm volatile("bcr 0,0"); +} + +int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) +{ + struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); + unsigned long stack_addr = (unsigned long)(kcb->jprobe_saved_r15); + + /* Put the regs back */ + memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs)); + /* put the stack back */ + memcpy((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack, + MIN_STACK_SIZE(stack_addr)); + preempt_enable_no_resched(); + return 1; +} + +static struct kprobe trampoline_p = { + .addr = (kprobe_opcode_t *) & kretprobe_trampoline, + .pre_handler = trampoline_probe_handler +}; + +int __init arch_init_kprobes(void) +{ + return register_kprobe(&trampoline_p); +} diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index d3cbfa3005ec..6603fbb41d07 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -45,7 +45,7 @@ #include <asm/irq.h> #include <asm/timer.h> -asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); +asmlinkage void ret_from_fork(void) asm ("ret_from_fork"); /* * Return saved PC of a blocked thread. used in kernel/sched. @@ -177,7 +177,8 @@ void show_regs(struct pt_regs *regs) extern void kernel_thread_starter(void); -__asm__(".align 4\n" +asm( + ".align 4\n" "kernel_thread_starter:\n" " la 2,0(10)\n" " basr 14,9\n" diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S index 658e5ac484f9..0340477f3b08 100644 --- a/arch/s390/kernel/reipl.S +++ b/arch/s390/kernel/reipl.S @@ -8,63 +8,82 @@ #include <asm/lowcore.h> - .globl do_reipl -do_reipl: basr %r13,0 + .globl do_reipl_asm +do_reipl_asm: basr %r13,0 .Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) -.Lpg1: lctl %c6,%c6,.Lall-.Lpg0(%r13) - stctl %c0,%c0,.Lctlsave-.Lpg0(%r13) - ni .Lctlsave-.Lpg0(%r13),0xef - lctl %c0,%c0,.Lctlsave-.Lpg0(%r13) - lr %r1,%r2 - 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 - msch .Lschib-.Lpg0(%r13) - lhi %r0,5 -.Lssch: ssch .Liplorb-.Lpg0(%r13) + + # switch off lowcore protection + +.Lpg1: stctl %c0,%c0,.Lctlsave1-.Lpg0(%r13) + stctl %c0,%c0,.Lctlsave2-.Lpg0(%r13) + ni .Lctlsave1-.Lpg0(%r13),0xef + lctl %c0,%c0,.Lctlsave1-.Lpg0(%r13) + + # do store status of all registers + + stm %r0,%r15,__LC_GPREGS_SAVE_AREA + stctl %c0,%c15,__LC_CREGS_SAVE_AREA + mvc __LC_CREGS_SAVE_AREA(4),.Lctlsave2-.Lpg0(%r13) + stam %a0,%a15,__LC_AREGS_SAVE_AREA + stpx __LC_PREFIX_SAVE_AREA + stckc .Lclkcmp-.Lpg0(%r13) + mvc __LC_CLOCK_COMP_SAVE_AREA(8),.Lclkcmp-.Lpg0(%r13) + stpt __LC_CPU_TIMER_SAVE_AREA + st %r13, __LC_PSW_SAVE_AREA+4 + + lctl %c6,%c6,.Lall-.Lpg0(%r13) + lr %r1,%r2 + 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 + msch .Lschib-.Lpg0(%r13) + lhi %r0,5 +.Lssch: ssch .Liplorb-.Lpg0(%r13) jz .L001 - brct %r0,.Lssch + brct %r0,.Lssch bas %r14,.Ldisab-.Lpg0(%r13) -.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13) -.Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13) +.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13) +.Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13) .Lcont: c %r1,__LC_SUBCHANNEL_ID jnz .Ltpi clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13) jnz .Ltpi - tsch .Liplirb-.Lpg0(%r13) + tsch .Liplirb-.Lpg0(%r13) tm .Liplirb+9-.Lpg0(%r13),0xbf - jz .L002 - bas %r14,.Ldisab-.Lpg0(%r13) -.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 - jz .L003 - bas %r14,.Ldisab-.Lpg0(%r13) + jz .L002 + bas %r14,.Ldisab-.Lpg0(%r13) +.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 + jz .L003 + bas %r14,.Ldisab-.Lpg0(%r13) .L003: spx .Lnull-.Lpg0(%r13) - st %r1,__LC_SUBCHANNEL_ID - lpsw 0 - sigp 0,0,0(6) -.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) + st %r1,__LC_SUBCHANNEL_ID + lpsw 0 + sigp 0,0,0(6) +.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) lpsw .Ldispsw-.Lpg0(%r13) - .align 8 + .align 8 +.Lclkcmp: .quad 0x0000000000000000 .Lall: .long 0xff000000 -.Lnull: .long 0x00000000 -.Lctlsave: .long 0x00000000 - .align 8 -.Lnewpsw: .long 0x00080000,0x80000000+.Lpg1 -.Lpcnew: .long 0x00080000,0x80000000+.Lecs -.Lionew: .long 0x00080000,0x80000000+.Lcont +.Lnull: .long 0x00000000 +.Lctlsave1: .long 0x00000000 +.Lctlsave2: .long 0x00000000 + .align 8 +.Lnewpsw: .long 0x00080000,0x80000000+.Lpg1 +.Lpcnew: .long 0x00080000,0x80000000+.Lecs +.Lionew: .long 0x00080000,0x80000000+.Lcont .Lwaitpsw: .long 0x020a0000,0x00000000+.Ltpi -.Ldispsw: .long 0x000a0000,0x00000000 -.Liplccws: .long 0x02000000,0x60000018 - .long 0x08000008,0x20000001 +.Ldispsw: .long 0x000a0000,0x00000000 +.Liplccws: .long 0x02000000,0x60000018 + .long 0x08000008,0x20000001 .Liplorb: .long 0x0049504c,0x0040ff80 .long 0x00000000+.Liplccws -.Lschib: .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 +.Lschib: .long 0x00000000,0x00000000 + .long 0x00000000,0x00000000 + .long 0x00000000,0x00000000 + .long 0x00000000,0x00000000 + .long 0x00000000,0x00000000 + .long 0x00000000,0x00000000 .Liplirb: .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 @@ -73,6 +92,3 @@ do_reipl: basr %r13,0 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 - - - diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S index 4d090d60f3ef..de7435054f7c 100644 --- a/arch/s390/kernel/reipl64.S +++ b/arch/s390/kernel/reipl64.S @@ -4,56 +4,74 @@ * S390 version * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com) - Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) + Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) */ #include <asm/lowcore.h> - .globl do_reipl -do_reipl: basr %r13,0 -.Lpg0: lpswe .Lnewpsw-.Lpg0(%r13) + .globl do_reipl_asm +do_reipl_asm: basr %r13,0 + + # do store status of all registers + +.Lpg0: stg %r1,.Lregsave-.Lpg0(%r13) + lghi %r1,0x1000 + stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1) + lg %r0,.Lregsave-.Lpg0(%r13) + stg %r0,__LC_GPREGS_SAVE_AREA-0x1000+8(%r1) + stctg %c0,%c15,__LC_CREGS_SAVE_AREA-0x1000(%r1) + stam %a0,%a15,__LC_AREGS_SAVE_AREA-0x1000(%r1) + stpx __LC_PREFIX_SAVE_AREA-0x1000(%r1) + stfpc __LC_FP_CREG_SAVE_AREA-0x1000(%r1) + stckc .Lclkcmp-.Lpg0(%r13) + mvc __LC_CLOCK_COMP_SAVE_AREA-0x1000(8,%r1),.Lclkcmp-.Lpg0(%r13) + stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1) + stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1) + + lpswe .Lnewpsw-.Lpg0(%r13) .Lpg1: lctlg %c6,%c6,.Lall-.Lpg0(%r13) - stctg %c0,%c0,.Lctlsave-.Lpg0(%r13) - ni .Lctlsave+4-.Lpg0(%r13),0xef - lctlg %c0,%c0,.Lctlsave-.Lpg0(%r13) - lgr %r1,%r2 - mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) - stsch .Lschib-.Lpg0(%r13) - oi .Lschib+5-.Lpg0(%r13),0x84 -.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01 - msch .Lschib-.Lpg0(%r13) - lghi %r0,5 -.Lssch: ssch .Liplorb-.Lpg0(%r13) + stctg %c0,%c0,.Lregsave-.Lpg0(%r13) + ni .Lregsave+4-.Lpg0(%r13),0xef + lctlg %c0,%c0,.Lregsave-.Lpg0(%r13) + lgr %r1,%r2 + mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) + stsch .Lschib-.Lpg0(%r13) + oi .Lschib+5-.Lpg0(%r13),0x84 +.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01 + msch .Lschib-.Lpg0(%r13) + lghi %r0,5 +.Lssch: ssch .Liplorb-.Lpg0(%r13) jz .L001 - brct %r0,.Lssch + brct %r0,.Lssch bas %r14,.Ldisab-.Lpg0(%r13) -.L001: mvc __LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13) -.Ltpi: lpswe .Lwaitpsw-.Lpg0(%r13) +.L001: mvc __LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13) +.Ltpi: lpswe .Lwaitpsw-.Lpg0(%r13) .Lcont: c %r1,__LC_SUBCHANNEL_ID jnz .Ltpi clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13) jnz .Ltpi - tsch .Liplirb-.Lpg0(%r13) + tsch .Liplirb-.Lpg0(%r13) tm .Liplirb+9-.Lpg0(%r13),0xbf - jz .L002 - bas %r14,.Ldisab-.Lpg0(%r13) -.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 - jz .L003 - bas %r14,.Ldisab-.Lpg0(%r13) + jz .L002 + bas %r14,.Ldisab-.Lpg0(%r13) +.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 + jz .L003 + bas %r14,.Ldisab-.Lpg0(%r13) .L003: spx .Lnull-.Lpg0(%r13) - st %r1,__LC_SUBCHANNEL_ID - lhi %r1,0 # mode 0 = esa - slr %r0,%r0 # set cpuid to zero - sigp %r1,%r0,0x12 # switch to esa mode - lpsw 0 -.Ldisab: sll %r14,1 - srl %r14,1 # need to kill hi bit to avoid specification exceptions. - st %r14,.Ldispsw+12-.Lpg0(%r13) + st %r1,__LC_SUBCHANNEL_ID + lhi %r1,0 # mode 0 = esa + slr %r0,%r0 # set cpuid to zero + sigp %r1,%r0,0x12 # switch to esa mode + lpsw 0 +.Ldisab: sll %r14,1 + srl %r14,1 # need to kill hi bit to avoid specification exceptions. + st %r14,.Ldispsw+12-.Lpg0(%r13) lpswe .Ldispsw-.Lpg0(%r13) - .align 8 + .align 8 +.Lclkcmp: .quad 0x0000000000000000 .Lall: .quad 0x00000000ff000000 -.Lctlsave: .quad 0x0000000000000000 -.Lnull: .long 0x0000000000000000 - .align 16 +.Lregsave: .quad 0x0000000000000000 +.Lnull: .long 0x0000000000000000 + .align 16 /* * These addresses have to be 31 bit otherwise * the sigp will throw a specifcation exception @@ -63,26 +81,26 @@ do_reipl: basr %r13,0 * 31bit lpswe instruction a fact they appear to have * ommited from the pop. */ -.Lnewpsw: .quad 0x0000000080000000 - .quad .Lpg1 -.Lpcnew: .quad 0x0000000080000000 - .quad .Lecs -.Lionew: .quad 0x0000000080000000 - .quad .Lcont +.Lnewpsw: .quad 0x0000000080000000 + .quad .Lpg1 +.Lpcnew: .quad 0x0000000080000000 + .quad .Lecs +.Lionew: .quad 0x0000000080000000 + .quad .Lcont .Lwaitpsw: .quad 0x0202000080000000 - .quad .Ltpi -.Ldispsw: .quad 0x0002000080000000 - .quad 0x0000000000000000 -.Liplccws: .long 0x02000000,0x60000018 - .long 0x08000008,0x20000001 + .quad .Ltpi +.Ldispsw: .quad 0x0002000080000000 + .quad 0x0000000000000000 +.Liplccws: .long 0x02000000,0x60000018 + .long 0x08000008,0x20000001 .Liplorb: .long 0x0049504c,0x0040ff80 .long 0x00000000+.Liplccws -.Lschib: .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 - .long 0x00000000,0x00000000 +.Lschib: .long 0x00000000,0x00000000 + .long 0x00000000,0x00000000 + .long 0x00000000,0x00000000 + .long 0x00000000,0x00000000 + .long 0x00000000,0x00000000 + .long 0x00000000,0x00000000 .Liplirb: .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 @@ -91,6 +109,3 @@ do_reipl: basr %r13,0 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 .long 0x00000000,0x00000000 - - - diff --git a/arch/s390/kernel/reipl_diag.c b/arch/s390/kernel/reipl_diag.c deleted file mode 100644 index 1f33951ba439..000000000000 --- a/arch/s390/kernel/reipl_diag.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file contains the implementation of the - * Linux re-IPL support - * - * (C) Copyright IBM Corp. 2005 - * - * Author(s): Volker Sameske (sameske@de.ibm.com) - * - */ - -#include <linux/kernel.h> - -static unsigned int reipl_diag_rc1; -static unsigned int reipl_diag_rc2; - -/* - * re-IPL the system using the last used IPL parameters - */ -void reipl_diag(void) -{ - asm volatile ( - " la %%r4,0\n" - " la %%r5,0\n" - " diag %%r4,%2,0x308\n" - "0:\n" - " st %%r4,%0\n" - " st %%r5,%1\n" - ".section __ex_table,\"a\"\n" -#ifdef CONFIG_64BIT - " .align 8\n" - " .quad 0b, 0b\n" -#else - " .align 4\n" - " .long 0b, 0b\n" -#endif - ".previous\n" - : "=m" (reipl_diag_rc1), "=m" (reipl_diag_rc2) - : "d" (3) : "cc", "4", "5" ); -} diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S index 2a25ec7147ff..f9899ff2e5b0 100644 --- a/arch/s390/kernel/relocate_kernel.S +++ b/arch/s390/kernel/relocate_kernel.S @@ -3,7 +3,7 @@ * * (C) Copyright IBM Corp. 2005 * - * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com> + * Author(s): Rolf Adelsberger, * Heiko Carstens <heiko.carstens@de.ibm.com> * */ @@ -24,14 +24,14 @@ .text .globl relocate_kernel relocate_kernel: - basr %r13,0 #base address + basr %r13,0 # base address .base: - stnsm sys_msk-.base(%r13),0xf8 #disable DAT and IRQ (external) - spx zero64-.base(%r13) #absolute addressing mode + stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQ (external) + spx zero64-.base(%r13) # absolute addressing mode stctl %c0,%c15,ctlregs-.base(%r13) stm %r0,%r15,gprregs-.base(%r13) la %r1,load_psw-.base(%r13) - mvc 0(8,%r0),0(%r1) + mvc 0(8,%r0),0(%r1) la %r0,.back-.base(%r13) st %r0,4(%r0) oi 4(%r0),0x80 @@ -51,50 +51,50 @@ .back_pgm: lm %r0,%r15,gprregs-.base(%r13) .start_reloc: - lhi %r10,-1 #preparing the mask - sll %r10,12 #shift it such that it becomes 0xf000 + lhi %r10,-1 # preparing the mask + sll %r10,12 # shift it such that it becomes 0xf000 .top: - lhi %r7,4096 #load PAGE_SIZE in r7 - lhi %r9,4096 #load PAGE_SIZE in r9 - l %r5,0(%r2) #read another word for indirection page - ahi %r2,4 #increment pointer - tml %r5,0x1 #is it a destination page? - je .indir_check #NO, goto "indir_check" - lr %r6,%r5 #r6 = r5 - nr %r6,%r10 #mask it out and... - j .top #...next iteration + lhi %r7,4096 # load PAGE_SIZE in r7 + lhi %r9,4096 # load PAGE_SIZE in r9 + l %r5,0(%r2) # read another word for indirection page + ahi %r2,4 # increment pointer + tml %r5,0x1 # is it a destination page? + je .indir_check # NO, goto "indir_check" + lr %r6,%r5 # r6 = r5 + nr %r6,%r10 # mask it out and... + j .top # ...next iteration .indir_check: - tml %r5,0x2 #is it a indirection page? - je .done_test #NO, goto "done_test" - nr %r5,%r10 #YES, mask out, - lr %r2,%r5 #move it into the right register, - j .top #and read next... + tml %r5,0x2 # is it a indirection page? + je .done_test # NO, goto "done_test" + nr %r5,%r10 # YES, mask out, + lr %r2,%r5 # move it into the right register, + j .top # and read next... .done_test: - tml %r5,0x4 #is it the done indicator? - je .source_test #NO! Well, then it should be the source indicator... - j .done #ok, lets finish it here... + tml %r5,0x4 # is it the done indicator? + je .source_test # NO! Well, then it should be the source indicator... + j .done # ok, lets finish it here... .source_test: - tml %r5,0x8 #it should be a source indicator... - je .top #NO, ignore it... - lr %r8,%r5 #r8 = r5 - nr %r8,%r10 #masking - 0: mvcle %r6,%r8,0x0 #copy PAGE_SIZE bytes from r8 to r6 - pad with 0 + tml %r5,0x8 # it should be a source indicator... + je .top # NO, ignore it... + lr %r8,%r5 # r8 = r5 + nr %r8,%r10 # masking + 0: mvcle %r6,%r8,0x0 # copy PAGE_SIZE bytes from r8 to r6 - pad with 0 jo 0b j .top .done: - sr %r0,%r0 #clear register r0 - la %r4,load_psw-.base(%r13) #load psw-address into the register - o %r3,4(%r4) #or load address into psw + sr %r0,%r0 # clear register r0 + la %r4,load_psw-.base(%r13) # load psw-address into the register + o %r3,4(%r4) # or load address into psw st %r3,4(%r4) - mvc 0(8,%r0),0(%r4) #copy psw to absolute address 0 + mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0 tm have_diag308-.base(%r13),0x01 jno .no_diag308 diag %r0,%r0,0x308 .no_diag308: - sr %r1,%r1 #clear %r1 - sr %r2,%r2 #clear %r2 - sigp %r1,%r2,0x12 #set cpuid to zero - lpsw 0 #hopefully start new kernel... + sr %r1,%r1 # clear %r1 + sr %r2,%r2 # clear %r2 + sigp %r1,%r2,0x12 # set cpuid to zero + lpsw 0 # hopefully start new kernel... .align 8 zero64: diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S index 8cdb86e8911f..4fb443042d9c 100644 --- a/arch/s390/kernel/relocate_kernel64.S +++ b/arch/s390/kernel/relocate_kernel64.S @@ -3,7 +3,7 @@ * * (C) Copyright IBM Corp. 2005 * - * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com> + * Author(s): Rolf Adelsberger, * Heiko Carstens <heiko.carstens@de.ibm.com> * */ @@ -25,10 +25,10 @@ .text .globl relocate_kernel relocate_kernel: - basr %r13,0 #base address + basr %r13,0 # base address .base: - stnsm sys_msk-.base(%r13),0xf8 #disable DAT and IRQs - spx zero64-.base(%r13) #absolute addressing mode + stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQs + spx zero64-.base(%r13) # absolute addressing mode stctg %c0,%c15,ctlregs-.base(%r13) stmg %r0,%r15,gprregs-.base(%r13) lghi %r0,3 @@ -37,16 +37,16 @@ la %r0,.back_pgm-.base(%r13) stg %r0,0x1d8(%r0) la %r1,load_psw-.base(%r13) - mvc 0(8,%r0),0(%r1) + mvc 0(8,%r0),0(%r1) la %r0,.back-.base(%r13) st %r0,4(%r0) oi 4(%r0),0x80 lghi %r0,0 diag %r0,%r0,0x308 .back: - lhi %r1,1 #mode 1 = esame - sigp %r1,%r0,0x12 #switch to esame mode - sam64 #switch to 64 bit addressing mode + lhi %r1,1 # mode 1 = esame + sigp %r1,%r0,0x12 # switch to esame mode + sam64 # switch to 64 bit addressing mode basr %r13,0 .back_base: oi have_diag308-.back_base(%r13),0x01 @@ -56,50 +56,50 @@ .back_pgm: lmg %r0,%r15,gprregs-.base(%r13) .top: - lghi %r7,4096 #load PAGE_SIZE in r7 - lghi %r9,4096 #load PAGE_SIZE in r9 - lg %r5,0(%r2) #read another word for indirection page - aghi %r2,8 #increment pointer - tml %r5,0x1 #is it a destination page? - je .indir_check #NO, goto "indir_check" - lgr %r6,%r5 #r6 = r5 - nill %r6,0xf000 #mask it out and... - j .top #...next iteration + lghi %r7,4096 # load PAGE_SIZE in r7 + lghi %r9,4096 # load PAGE_SIZE in r9 + lg %r5,0(%r2) # read another word for indirection page + aghi %r2,8 # increment pointer + tml %r5,0x1 # is it a destination page? + je .indir_check # NO, goto "indir_check" + lgr %r6,%r5 # r6 = r5 + nill %r6,0xf000 # mask it out and... + j .top # ...next iteration .indir_check: - tml %r5,0x2 #is it a indirection page? - je .done_test #NO, goto "done_test" - nill %r5,0xf000 #YES, mask out, - lgr %r2,%r5 #move it into the right register, - j .top #and read next... + tml %r5,0x2 # is it a indirection page? + je .done_test # NO, goto "done_test" + nill %r5,0xf000 # YES, mask out, + lgr %r2,%r5 # move it into the right register, + j .top # and read next... .done_test: - tml %r5,0x4 #is it the done indicator? - je .source_test #NO! Well, then it should be the source indicator... - j .done #ok, lets finish it here... + tml %r5,0x4 # is it the done indicator? + je .source_test # NO! Well, then it should be the source indicator... + j .done # ok, lets finish it here... .source_test: - tml %r5,0x8 #it should be a source indicator... - je .top #NO, ignore it... - lgr %r8,%r5 #r8 = r5 - nill %r8,0xf000 #masking - 0: mvcle %r6,%r8,0x0 #copy PAGE_SIZE bytes from r8 to r6 - pad with 0 + tml %r5,0x8 # it should be a source indicator... + je .top # NO, ignore it... + lgr %r8,%r5 # r8 = r5 + nill %r8,0xf000 # masking + 0: mvcle %r6,%r8,0x0 # copy PAGE_SIZE bytes from r8 to r6 - pad with 0 jo 0b - j .top + j .top .done: - sgr %r0,%r0 #clear register r0 - la %r4,load_psw-.base(%r13) #load psw-address into the register - o %r3,4(%r4) #or load address into psw + sgr %r0,%r0 # clear register r0 + la %r4,load_psw-.base(%r13) # load psw-address into the register + o %r3,4(%r4) # or load address into psw st %r3,4(%r4) - mvc 0(8,%r0),0(%r4) #copy psw to absolute address 0 + mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0 tm have_diag308-.base(%r13),0x01 jno .no_diag308 diag %r0,%r0,0x308 .no_diag308: - sam31 #31 bit mode - sr %r1,%r1 #erase register r1 - sr %r2,%r2 #erase register r2 - sigp %r1,%r2,0x12 #set cpuid to zero - lpsw 0 #hopefully start new kernel... + sam31 # 31 bit mode + sr %r1,%r1 # erase register r1 + sr %r2,%r2 # erase register r2 + sigp %r1,%r2,0x12 # set cpuid to zero + lpsw 0 # hopefully start new kernel... - .align 8 + .align 8 zero64: .quad 0 load_psw: diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c index c73a45467fa4..9f19e833a562 100644 --- a/arch/s390/kernel/s390_ksyms.c +++ b/arch/s390/kernel/s390_ksyms.c @@ -25,12 +25,6 @@ EXPORT_SYMBOL(_oi_bitmap); EXPORT_SYMBOL(_ni_bitmap); EXPORT_SYMBOL(_zb_findmap); EXPORT_SYMBOL(_sb_findmap); -EXPORT_SYMBOL(__copy_from_user_asm); -EXPORT_SYMBOL(__copy_to_user_asm); -EXPORT_SYMBOL(__copy_in_user_asm); -EXPORT_SYMBOL(__clear_user_asm); -EXPORT_SYMBOL(__strncpy_from_user_asm); -EXPORT_SYMBOL(__strnlen_user_asm); EXPORT_SYMBOL(diag10); /* diff --git a/arch/s390/kernel/semaphore.c b/arch/s390/kernel/semaphore.c index 8dfb690c159f..191303f6c1d8 100644 --- a/arch/s390/kernel/semaphore.c +++ b/arch/s390/kernel/semaphore.c @@ -26,17 +26,17 @@ static inline int __sem_update_count(struct semaphore *sem, int incr) { int old_val, new_val; - __asm__ __volatile__(" l %0,0(%3)\n" - "0: ltr %1,%0\n" - " jhe 1f\n" - " lhi %1,0\n" - "1: ar %1,%4\n" - " cs %0,%1,0(%3)\n" - " jl 0b\n" - : "=&d" (old_val), "=&d" (new_val), - "=m" (sem->count) - : "a" (&sem->count), "d" (incr), "m" (sem->count) - : "cc" ); + asm volatile( + " l %0,0(%3)\n" + "0: ltr %1,%0\n" + " jhe 1f\n" + " lhi %1,0\n" + "1: ar %1,%4\n" + " cs %0,%1,0(%3)\n" + " jl 0b\n" + : "=&d" (old_val), "=&d" (new_val), "=m" (sem->count) + : "a" (&sem->count), "d" (incr), "m" (sem->count) + : "cc"); return old_val; } diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index c902f059c7aa..a21cfbb9d97e 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -37,6 +37,7 @@ #include <linux/kernel_stat.h> #include <linux/device.h> #include <linux/notifier.h> +#include <linux/pfn.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -50,6 +51,12 @@ #include <asm/sections.h> /* + * User copy operations. + */ +struct uaccess_ops uaccess; +EXPORT_SYMBOL_GPL(uaccess); + +/* * Machine setup.. */ unsigned int console_mode = 0; @@ -94,7 +101,7 @@ void __devinit 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)); + asm volatile("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id)); S390_lowcore.cpu_data.cpu_addr = addr; /* @@ -284,16 +291,9 @@ void (*_machine_power_off)(void) = machine_power_off_smp; /* * Reboot, halt and power_off routines for non SMP. */ -extern void reipl(unsigned long devno); -extern void reipl_diag(void); static void do_machine_restart_nonsmp(char * __unused) { - reipl_diag(); - - if (MACHINE_IS_VM) - cpcmd ("IPL", NULL, 0, NULL); - else - reipl (0x10000 | S390_lowcore.ipl_device); + do_reipl(); } static void do_machine_halt_nonsmp(void) @@ -501,13 +501,47 @@ setup_memory(void) * partially used pages are not usable - thus * we are rounding upwards: */ - start_pfn = (__pa(&_end) + PAGE_SIZE - 1) >> PAGE_SHIFT; - end_pfn = max_pfn = memory_end >> PAGE_SHIFT; + start_pfn = PFN_UP(__pa(&_end)); + end_pfn = max_pfn = PFN_DOWN(memory_end); /* Initialize storage key for kernel pages */ for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++) page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); +#ifdef CONFIG_BLK_DEV_INITRD + /* + * Move the initrd in case the bitmap of the bootmem allocater + * would overwrite it. + */ + + if (INITRD_START && INITRD_SIZE) { + unsigned long bmap_size; + unsigned long start; + + bmap_size = bootmem_bootmap_pages(end_pfn - start_pfn + 1); + bmap_size = PFN_PHYS(bmap_size); + + if (PFN_PHYS(start_pfn) + bmap_size > INITRD_START) { + start = PFN_PHYS(start_pfn) + bmap_size + PAGE_SIZE; + + if (start + INITRD_SIZE > memory_end) { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\n" + "disabling initrd\n", + start + INITRD_SIZE, memory_end); + INITRD_START = INITRD_SIZE = 0; + } else { + printk("Moving initrd (0x%08lx -> 0x%08lx, " + "size: %ld)\n", + INITRD_START, start, INITRD_SIZE); + memmove((void *) start, (void *) INITRD_START, + INITRD_SIZE); + INITRD_START = start; + } + } + } +#endif + /* * Initialize the boot-time allocator (with low memory only): */ @@ -559,7 +593,7 @@ setup_memory(void) reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size); #ifdef CONFIG_BLK_DEV_INITRD - if (INITRD_START) { + if (INITRD_START && INITRD_SIZE) { if (INITRD_START + INITRD_SIZE <= memory_end) { reserve_bootmem(INITRD_START, INITRD_SIZE); initrd_start = INITRD_START; @@ -613,6 +647,11 @@ setup_arch(char **cmdline_p) memory_end = memory_size; + if (MACHINE_HAS_MVCOS) + memcpy(&uaccess, &uaccess_mvcos, sizeof(uaccess)); + else + memcpy(&uaccess, &uaccess_std, sizeof(uaccess)); + parse_early_param(); #ifndef CONFIG_64BIT @@ -720,214 +759,3 @@ struct seq_operations cpuinfo_op = { .show = show_cpuinfo, }; -#define DEFINE_IPL_ATTR(_name, _format, _value) \ -static ssize_t ipl_##_name##_show(struct subsystem *subsys, \ - char *page) \ -{ \ - return sprintf(page, _format, _value); \ -} \ -static struct subsys_attribute ipl_##_name##_attr = \ - __ATTR(_name, S_IRUGO, ipl_##_name##_show, NULL); - -DEFINE_IPL_ATTR(wwpn, "0x%016llx\n", (unsigned long long) - IPL_PARMBLOCK_START->fcp.wwpn); -DEFINE_IPL_ATTR(lun, "0x%016llx\n", (unsigned long long) - IPL_PARMBLOCK_START->fcp.lun); -DEFINE_IPL_ATTR(bootprog, "%lld\n", (unsigned long long) - IPL_PARMBLOCK_START->fcp.bootprog); -DEFINE_IPL_ATTR(br_lba, "%lld\n", (unsigned long long) - IPL_PARMBLOCK_START->fcp.br_lba); - -enum ipl_type_type { - ipl_type_unknown, - ipl_type_ccw, - ipl_type_fcp, -}; - -static enum ipl_type_type -get_ipl_type(void) -{ - struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; - - if (!IPL_DEVNO_VALID) - return ipl_type_unknown; - if (!IPL_PARMBLOCK_VALID) - return ipl_type_ccw; - if (ipl->hdr.header.version > IPL_MAX_SUPPORTED_VERSION) - return ipl_type_unknown; - if (ipl->fcp.pbt != IPL_TYPE_FCP) - return ipl_type_unknown; - return ipl_type_fcp; -} - -static ssize_t -ipl_type_show(struct subsystem *subsys, char *page) -{ - switch (get_ipl_type()) { - case ipl_type_ccw: - return sprintf(page, "ccw\n"); - case ipl_type_fcp: - return sprintf(page, "fcp\n"); - default: - return sprintf(page, "unknown\n"); - } -} - -static struct subsys_attribute ipl_type_attr = __ATTR_RO(ipl_type); - -static ssize_t -ipl_device_show(struct subsystem *subsys, char *page) -{ - struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; - - switch (get_ipl_type()) { - case ipl_type_ccw: - return sprintf(page, "0.0.%04x\n", ipl_devno); - case ipl_type_fcp: - return sprintf(page, "0.0.%04x\n", ipl->fcp.devno); - default: - return 0; - } -} - -static struct subsys_attribute ipl_device_attr = - __ATTR(device, S_IRUGO, ipl_device_show, NULL); - -static struct attribute *ipl_fcp_attrs[] = { - &ipl_type_attr.attr, - &ipl_device_attr.attr, - &ipl_wwpn_attr.attr, - &ipl_lun_attr.attr, - &ipl_bootprog_attr.attr, - &ipl_br_lba_attr.attr, - NULL, -}; - -static struct attribute_group ipl_fcp_attr_group = { - .attrs = ipl_fcp_attrs, -}; - -static struct attribute *ipl_ccw_attrs[] = { - &ipl_type_attr.attr, - &ipl_device_attr.attr, - NULL, -}; - -static struct attribute_group ipl_ccw_attr_group = { - .attrs = ipl_ccw_attrs, -}; - -static struct attribute *ipl_unknown_attrs[] = { - &ipl_type_attr.attr, - NULL, -}; - -static struct attribute_group ipl_unknown_attr_group = { - .attrs = ipl_unknown_attrs, -}; - -static ssize_t -ipl_parameter_read(struct kobject *kobj, char *buf, loff_t off, size_t count) -{ - unsigned int size = IPL_PARMBLOCK_SIZE; - - if (off > size) - return 0; - if (off + count > size) - count = size - off; - - memcpy(buf, (void *) IPL_PARMBLOCK_START + off, count); - return count; -} - -static struct bin_attribute ipl_parameter_attr = { - .attr = { - .name = "binary_parameter", - .mode = S_IRUGO, - .owner = THIS_MODULE, - }, - .size = PAGE_SIZE, - .read = &ipl_parameter_read, -}; - -static ssize_t -ipl_scp_data_read(struct kobject *kobj, char *buf, loff_t off, size_t count) -{ - unsigned int size = IPL_PARMBLOCK_START->fcp.scp_data_len; - void *scp_data = &IPL_PARMBLOCK_START->fcp.scp_data; - - if (off > size) - return 0; - if (off + count > size) - count = size - off; - - memcpy(buf, scp_data + off, count); - return count; -} - -static struct bin_attribute ipl_scp_data_attr = { - .attr = { - .name = "scp_data", - .mode = S_IRUGO, - .owner = THIS_MODULE, - }, - .size = PAGE_SIZE, - .read = &ipl_scp_data_read, -}; - -static decl_subsys(ipl, NULL, NULL); - -static int ipl_register_fcp_files(void) -{ - int rc; - - rc = sysfs_create_group(&ipl_subsys.kset.kobj, - &ipl_fcp_attr_group); - if (rc) - goto out; - rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj, - &ipl_parameter_attr); - if (rc) - goto out_ipl_parm; - rc = sysfs_create_bin_file(&ipl_subsys.kset.kobj, - &ipl_scp_data_attr); - if (!rc) - goto out; - - sysfs_remove_bin_file(&ipl_subsys.kset.kobj, &ipl_parameter_attr); - -out_ipl_parm: - sysfs_remove_group(&ipl_subsys.kset.kobj, &ipl_fcp_attr_group); -out: - return rc; -} - -static int __init -ipl_device_sysfs_register(void) { - int rc; - - rc = firmware_register(&ipl_subsys); - if (rc) - goto out; - - switch (get_ipl_type()) { - case ipl_type_ccw: - rc = sysfs_create_group(&ipl_subsys.kset.kobj, - &ipl_ccw_attr_group); - break; - case ipl_type_fcp: - rc = ipl_register_fcp_files(); - break; - default: - rc = sysfs_create_group(&ipl_subsys.kset.kobj, - &ipl_unknown_attr_group); - break; - } - - if (rc) - firmware_unregister(&ipl_subsys); -out: - return rc; -} - -__initcall(ipl_device_sysfs_register); diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index a887b686f279..642095ec7c07 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -114,29 +114,26 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs) { unsigned long old_mask = regs->psw.mask; - int err; - + _sigregs user_sregs; + save_access_regs(current->thread.acrs); /* Copy a 'clean' PSW mask to the user to avoid leaking information about whether PER is currently on. */ regs->psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask); - err = __copy_to_user(&sregs->regs.psw, ®s->psw, - sizeof(sregs->regs.psw)+sizeof(sregs->regs.gprs)); + memcpy(&user_sregs.regs.psw, ®s->psw, sizeof(sregs->regs.psw) + + sizeof(sregs->regs.gprs)); regs->psw.mask = old_mask; - if (err != 0) - return err; - err = __copy_to_user(&sregs->regs.acrs, current->thread.acrs, - sizeof(sregs->regs.acrs)); - if (err != 0) - return err; + memcpy(&user_sregs.regs.acrs, current->thread.acrs, + sizeof(sregs->regs.acrs)); /* * We have to store the fp registers to current->thread.fp_regs * to merge them with the emulated registers. */ save_fp_regs(¤t->thread.fp_regs); - return __copy_to_user(&sregs->fpregs, ¤t->thread.fp_regs, - sizeof(s390_fp_regs)); + memcpy(&user_sregs.fpregs, ¤t->thread.fp_regs, + sizeof(s390_fp_regs)); + return __copy_to_user(sregs, &user_sregs, sizeof(_sigregs)); } /* Returns positive number on error */ @@ -144,27 +141,25 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs) { unsigned long old_mask = regs->psw.mask; int err; + _sigregs user_sregs; /* Alwys make any pending restarted system call return -EINTR */ current_thread_info()->restart_block.fn = do_no_restart_syscall; - err = __copy_from_user(®s->psw, &sregs->regs.psw, - sizeof(sregs->regs.psw)+sizeof(sregs->regs.gprs)); + err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs)); regs->psw.mask = PSW_MASK_MERGE(old_mask, regs->psw.mask); regs->psw.addr |= PSW_ADDR_AMODE; if (err) return err; - err = __copy_from_user(¤t->thread.acrs, &sregs->regs.acrs, - sizeof(sregs->regs.acrs)); - if (err) - return err; + memcpy(®s->psw, &user_sregs.regs.psw, sizeof(sregs->regs.psw) + + sizeof(sregs->regs.gprs)); + memcpy(¤t->thread.acrs, &user_sregs.regs.acrs, + sizeof(sregs->regs.acrs)); restore_access_regs(current->thread.acrs); - err = __copy_from_user(¤t->thread.fp_regs, &sregs->fpregs, - sizeof(s390_fp_regs)); + memcpy(¤t->thread.fp_regs, &user_sregs.fpregs, + sizeof(s390_fp_regs)); current->thread.fp_regs.fpc &= FPC_VALID_MASK; - if (err) - return err; restore_fp_regs(¤t->thread.fp_regs); regs->trap = -1; /* disable syscall checks */ @@ -457,6 +452,7 @@ void do_signal(struct pt_regs *regs) case -ERESTART_RESTARTBLOCK: regs->gprs[2] = -EINTR; } + regs->trap = -1; /* Don't deal with this again. */ } /* Get signal to deliver. When running under ptrace, at this point diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 8e03219eea76..a8e6199755d4 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -59,14 +59,11 @@ static struct task_struct *current_set[NR_CPUS]; extern char vmhalt_cmd[]; extern char vmpoff_cmd[]; -extern void reipl(unsigned long devno); -extern void reipl_diag(void); - static void smp_ext_bitcall(int, ec_bit_sig); static void smp_ext_bitcall_others(ec_bit_sig); /* - * Structure and data for smp_call_function(). This is designed to minimise +5B * Structure and data for smp_call_function(). This is designed to minimise * static memory requirements. It also looks cleaner. */ static DEFINE_SPINLOCK(call_lock); @@ -279,12 +276,7 @@ static void do_machine_restart(void * __unused) * interrupted by an external interrupt and s390irq * locks are always held disabled). */ - reipl_diag(); - - if (MACHINE_IS_VM) - cpcmd ("IPL", NULL, 0, NULL); - else - reipl (0x10000 | S390_lowcore.ipl_device); + do_reipl(); } void machine_restart_smp(char * __unused) @@ -426,59 +418,49 @@ void smp_send_reschedule(int cpu) /* * parameter area for the set/clear control bit callbacks */ -typedef struct -{ - __u16 start_ctl; - __u16 end_ctl; +struct ec_creg_mask_parms { unsigned long orvals[16]; unsigned long andvals[16]; -} ec_creg_mask_parms; +}; /* * callback for setting/clearing control bits */ void smp_ctl_bit_callback(void *info) { - ec_creg_mask_parms *pp; + struct ec_creg_mask_parms *pp = info; unsigned long cregs[16]; int i; - pp = (ec_creg_mask_parms *) info; - __ctl_store(cregs[pp->start_ctl], pp->start_ctl, pp->end_ctl); - for (i = pp->start_ctl; i <= pp->end_ctl; i++) + __ctl_store(cregs, 0, 15); + for (i = 0; i <= 15; i++) cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i]; - __ctl_load(cregs[pp->start_ctl], pp->start_ctl, pp->end_ctl); + __ctl_load(cregs, 0, 15); } /* * Set a bit in a control register of all cpus */ -void smp_ctl_set_bit(int cr, int bit) { - ec_creg_mask_parms parms; +void smp_ctl_set_bit(int cr, int bit) +{ + struct ec_creg_mask_parms parms; - parms.start_ctl = cr; - parms.end_ctl = cr; + memset(&parms.orvals, 0, sizeof(parms.orvals)); + memset(&parms.andvals, 0xff, sizeof(parms.andvals)); parms.orvals[cr] = 1 << bit; - parms.andvals[cr] = -1L; - preempt_disable(); - smp_call_function(smp_ctl_bit_callback, &parms, 0, 1); - __ctl_set_bit(cr, bit); - preempt_enable(); + on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1); } /* * Clear a bit in a control register of all cpus */ -void smp_ctl_clear_bit(int cr, int bit) { - ec_creg_mask_parms parms; +void smp_ctl_clear_bit(int cr, int bit) +{ + struct ec_creg_mask_parms parms; - parms.start_ctl = cr; - parms.end_ctl = cr; - parms.orvals[cr] = 0; + memset(&parms.orvals, 0, sizeof(parms.orvals)); + memset(&parms.andvals, 0xff, sizeof(parms.andvals)); parms.andvals[cr] = ~(1L << bit); - preempt_disable(); - smp_call_function(smp_ctl_bit_callback, &parms, 0, 1); - __ctl_clear_bit(cr, bit); - preempt_enable(); + on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1); } /* @@ -658,9 +640,9 @@ __cpu_up(unsigned int cpu) sf->gprs[9] = (unsigned long) sf; cpu_lowcore->save_area[15] = (unsigned long) sf; __ctl_store(cpu_lowcore->cregs_save_area[0], 0, 15); - __asm__ __volatile__("stam 0,15,0(%0)" - : : "a" (&cpu_lowcore->access_regs_save_area) - : "memory"); + asm volatile( + " stam 0,15,0(%0)" + : : "a" (&cpu_lowcore->access_regs_save_area) : "memory"); cpu_lowcore->percpu_offset = __per_cpu_offset[cpu]; cpu_lowcore->current_task = (unsigned long) idle; cpu_lowcore->cpu_data.cpu_nr = cpu; @@ -716,7 +698,7 @@ int __cpu_disable(void) { unsigned long flags; - ec_creg_mask_parms cr_parms; + struct ec_creg_mask_parms cr_parms; int cpu = smp_processor_id(); spin_lock_irqsave(&smp_reserve_lock, flags); @@ -732,30 +714,21 @@ __cpu_disable(void) pfault_fini(); #endif - /* disable all external interrupts */ + memset(&cr_parms.orvals, 0, sizeof(cr_parms.orvals)); + memset(&cr_parms.andvals, 0xff, sizeof(cr_parms.andvals)); - cr_parms.start_ctl = 0; - cr_parms.end_ctl = 0; + /* disable all external interrupts */ cr_parms.orvals[0] = 0; cr_parms.andvals[0] = ~(1<<15 | 1<<14 | 1<<13 | 1<<12 | 1<<11 | 1<<10 | 1<< 6 | 1<< 4); - smp_ctl_bit_callback(&cr_parms); - /* disable all I/O interrupts */ - - cr_parms.start_ctl = 6; - cr_parms.end_ctl = 6; cr_parms.orvals[6] = 0; cr_parms.andvals[6] = ~(1<<31 | 1<<30 | 1<<29 | 1<<28 | 1<<27 | 1<<26 | 1<<25 | 1<<24); - smp_ctl_bit_callback(&cr_parms); - /* disable most machine checks */ - - cr_parms.start_ctl = 14; - cr_parms.end_ctl = 14; cr_parms.orvals[14] = 0; cr_parms.andvals[14] = ~(1<<28 | 1<<27 | 1<<26 | 1<<25 | 1<<24); + smp_ctl_bit_callback(&cr_parms); spin_unlock_irqrestore(&smp_reserve_lock, flags); diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index de83f38288d0..d9428a0fc8fb 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -59,9 +59,7 @@ static inline unsigned long save_context_stack(struct stack_trace *trace, } } -void save_stack_trace(struct stack_trace *trace, - struct task_struct *task, int all_contexts, - unsigned int skip) +void save_stack_trace(struct stack_trace *trace, struct task_struct *task) { register unsigned long sp asm ("15"); unsigned long orig_sp; @@ -69,22 +67,23 @@ void save_stack_trace(struct stack_trace *trace, sp &= PSW_ADDR_INSN; orig_sp = sp; - sp = save_context_stack(trace, &skip, sp, + sp = save_context_stack(trace, &trace->skip, sp, S390_lowcore.panic_stack - PAGE_SIZE, S390_lowcore.panic_stack); - if ((sp != orig_sp) && !all_contexts) + if ((sp != orig_sp) && !trace->all_contexts) return; - sp = save_context_stack(trace, &skip, sp, + sp = save_context_stack(trace, &trace->skip, sp, S390_lowcore.async_stack - ASYNC_SIZE, S390_lowcore.async_stack); - if ((sp != orig_sp) && !all_contexts) + if ((sp != orig_sp) && !trace->all_contexts) return; if (task) - save_context_stack(trace, &skip, sp, + save_context_stack(trace, &trace->skip, sp, (unsigned long) task_stack_page(task), (unsigned long) task_stack_page(task) + THREAD_SIZE); else - save_context_stack(trace, &skip, sp, S390_lowcore.thread_info, + save_context_stack(trace, &trace->skip, sp, + S390_lowcore.thread_info, S390_lowcore.thread_info + THREAD_SIZE); return; } diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 74e6178fbaf2..4bf66cc4a267 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -53,8 +53,6 @@ static u64 init_timer_cc; static u64 jiffies_timer_cc; static u64 xtime_cc; -extern unsigned long wall_jiffies; - /* * Scheduler clock - returns current time in nanosec units. */ @@ -87,9 +85,8 @@ static inline unsigned long do_gettimeoffset(void) { __u64 now; - now = (get_clock() - jiffies_timer_cc) >> 12; - /* We require the offset from the latest update of xtime */ - now -= (__u64) wall_jiffies*USECS_PER_JIFFY; + now = (get_clock() - jiffies_timer_cc) >> 12; + now -= (__u64) jiffies * USECS_PER_JIFFY; return (unsigned long) now; } @@ -166,7 +163,7 @@ EXPORT_SYMBOL(do_settimeofday); void account_ticks(struct pt_regs *regs) { __u64 tmp; - __u32 ticks, xticks; + __u32 ticks; /* Calculate how many ticks have passed. */ if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) { @@ -204,6 +201,7 @@ void account_ticks(struct pt_regs *regs) */ write_seqlock(&xtime_lock); if (S390_lowcore.jiffy_timer > xtime_cc) { + __u32 xticks; tmp = S390_lowcore.jiffy_timer - xtime_cc; if (tmp >= 2*CLK_TICKS_PER_JIFFY) { xticks = __div(tmp, CLK_TICKS_PER_JIFFY); @@ -212,13 +210,11 @@ void account_ticks(struct pt_regs *regs) xticks = 1; xtime_cc += CLK_TICKS_PER_JIFFY; } - while (xticks--) - do_timer(regs); + do_timer(xticks); } write_sequnlock(&xtime_lock); #else - for (xticks = ticks; xticks > 0; xticks--) - do_timer(regs); + do_timer(ticks); #endif #ifdef CONFIG_VIRT_CPU_ACCOUNTING @@ -351,10 +347,12 @@ void __init time_init(void) int cc; /* kick the TOD clock */ - asm volatile ("STCK 0(%1)\n\t" - "IPM %0\n\t" - "SRL %0,28" : "=r" (cc) : "a" (&init_timer_cc) - : "memory", "cc"); + asm volatile( + " stck 0(%2)\n" + " ipm %0\n" + " srl %0,28" + : "=d" (cc), "=m" (init_timer_cc) + : "a" (&init_timer_cc) : "cc"); switch (cc) { case 0: /* clock in set state: all is fine */ break; diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index bde1d1d59858..3eb4fab048b8 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -29,6 +29,7 @@ #include <linux/module.h> #include <linux/kallsyms.h> #include <linux/reboot.h> +#include <linux/kprobes.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -39,6 +40,7 @@ #include <asm/s390_ext.h> #include <asm/lowcore.h> #include <asm/debug.h> +#include <asm/kdebug.h> /* Called from entry.S only */ extern void handle_per_exception(struct pt_regs *regs); @@ -74,6 +76,20 @@ static int kstack_depth_to_print = 12; static int kstack_depth_to_print = 20; #endif /* CONFIG_64BIT */ +ATOMIC_NOTIFIER_HEAD(s390die_chain); + +int register_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&s390die_chain, nb); +} +EXPORT_SYMBOL(register_die_notifier); + +int unregister_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&s390die_chain, nb); +} +EXPORT_SYMBOL(unregister_die_notifier); + /* * For show_trace we have tree different stack to consider: * - the panic stack which is used if the kernel stack has overflown @@ -305,8 +321,9 @@ report_user_fault(long interruption_code, struct pt_regs *regs) #endif } -static void inline do_trap(long interruption_code, int signr, char *str, - struct pt_regs *regs, siginfo_t *info) +static void __kprobes inline do_trap(long interruption_code, int signr, + char *str, struct pt_regs *regs, + siginfo_t *info) { /* * We got all needed information from the lowcore and can @@ -315,6 +332,10 @@ static void inline do_trap(long interruption_code, int signr, char *str, if (regs->psw.mask & PSW_MASK_PSTATE) local_irq_enable(); + if (notify_die(DIE_TRAP, str, regs, interruption_code, + interruption_code, signr) == NOTIFY_STOP) + return; + if (regs->psw.mask & PSW_MASK_PSTATE) { struct task_struct *tsk = current; @@ -336,8 +357,12 @@ static inline void __user *get_check_address(struct pt_regs *regs) return (void __user *)((regs->psw.addr-S390_lowcore.pgm_ilc) & PSW_ADDR_INSN); } -void do_single_step(struct pt_regs *regs) +void __kprobes do_single_step(struct pt_regs *regs) { + if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, + SIGTRAP) == NOTIFY_STOP){ + return; + } if ((current->ptrace & PT_PTRACED) != 0) force_sig(SIGTRAP, current); } @@ -572,8 +597,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) local_irq_enable(); if (MACHINE_HAS_IEEE) - __asm__ volatile ("stfpc %0\n\t" - : "=m" (current->thread.fp_regs.fpc)); + asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); #ifdef CONFIG_MATHEMU else if (regs->psw.mask & PSW_MASK_PSTATE) { diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index ff5f7bb34f75..af9e69a03011 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -24,6 +24,7 @@ SECTIONS *(.text) SCHED_TEXT LOCK_TEXT + KPROBES_TEXT *(.fixup) *(.gnu.warning) } = 0x0700 @@ -117,7 +118,7 @@ SECTIONS /* Sections to be discarded */ /DISCARD/ : { - *(.exitcall.exit) + *(.exit.text) *(.exit.data) *(.exitcall.exit) } /* Stabs debugging sections. */ diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index e05d087a6eae..b0cfa6c4883d 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile @@ -4,6 +4,7 @@ EXTRA_AFLAGS := -traditional -lib-y += delay.o string.o -lib-y += $(if $(CONFIG_64BIT),uaccess64.o,uaccess.o) +lib-y += delay.o string.o uaccess_std.o +lib-$(CONFIG_32BIT) += div64.o +lib-$(CONFIG_64BIT) += uaccess_mvcos.o lib-$(CONFIG_SMP) += spinlock.o diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 468f4ea33f99..027c4742a001 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -27,9 +27,7 @@ void __delay(unsigned long loops) * 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) + 1)); + asm volatile("0: brct %0,0b" : : "d" ((loops/2) + 1)); } /* @@ -38,13 +36,12 @@ void __delay(unsigned long loops) */ void __udelay(unsigned long usecs) { - uint64_t start_cc, end_cc; + uint64_t start_cc; if (usecs == 0) return; - asm volatile ("STCK %0" : "=m" (start_cc)); + start_cc = get_clock(); do { cpu_relax(); - asm volatile ("STCK %0" : "=m" (end_cc)); - } while (((end_cc - start_cc)/4096) < usecs); + } while (((get_clock() - start_cc)/4096) < usecs); } diff --git a/arch/s390/lib/div64.c b/arch/s390/lib/div64.c new file mode 100644 index 000000000000..0481f3424a13 --- /dev/null +++ b/arch/s390/lib/div64.c @@ -0,0 +1,151 @@ +/* + * arch/s390/lib/div64.c + * + * __div64_32 implementation for 31 bit. + * + * Copyright (C) IBM Corp. 2006 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + */ + +#include <linux/types.h> +#include <linux/module.h> + +#ifdef CONFIG_MARCH_G5 + +/* + * Function to divide an unsigned 64 bit integer by an unsigned + * 31 bit integer using signed 64/32 bit division. + */ +static uint32_t __div64_31(uint64_t *n, uint32_t base) +{ + register uint32_t reg2 asm("2"); + register uint32_t reg3 asm("3"); + uint32_t *words = (uint32_t *) n; + uint32_t tmp; + + /* Special case base==1, remainder = 0, quotient = n */ + if (base == 1) + return 0; + /* + * Special case base==0 will cause a fixed point divide exception + * on the dr instruction and may not happen anyway. For the + * following calculation we can assume base > 1. The first + * signed 64 / 32 bit division with an upper half of 0 will + * give the correct upper half of the 64 bit quotient. + */ + reg2 = 0UL; + reg3 = words[0]; + asm volatile( + " dr %0,%2\n" + : "+d" (reg2), "+d" (reg3) : "d" (base) : "cc" ); + words[0] = reg3; + reg3 = words[1]; + /* + * To get the lower half of the 64 bit quotient and the 32 bit + * remainder we have to use a little trick. Since we only have + * a signed division the quotient can get too big. To avoid this + * the 64 bit dividend is halved, then the signed division will + * work. Afterwards the quotient and the remainder are doubled. + * If the last bit of the dividend has been one the remainder + * is increased by one then checked against the base. If the + * remainder has overflown subtract base and increase the + * quotient. Simple, no ? + */ + asm volatile( + " nr %2,%1\n" + " srdl %0,1\n" + " dr %0,%3\n" + " alr %0,%0\n" + " alr %1,%1\n" + " alr %0,%2\n" + " clr %0,%3\n" + " jl 0f\n" + " slr %0,%3\n" + " alr %1,%2\n" + "0:\n" + : "+d" (reg2), "+d" (reg3), "=d" (tmp) + : "d" (base), "2" (1UL) : "cc" ); + words[1] = reg3; + return reg2; +} + +/* + * Function to divide an unsigned 64 bit integer by an unsigned + * 32 bit integer using the unsigned 64/31 bit division. + */ +uint32_t __div64_32(uint64_t *n, uint32_t base) +{ + uint32_t r; + + /* + * If the most significant bit of base is set, divide n by + * (base/2). That allows to use 64/31 bit division and gives a + * good approximation of the result: n = (base/2)*q + r. The + * result needs to be corrected with two simple transformations. + * If base is already < 2^31-1 __div64_31 can be used directly. + */ + r = __div64_31(n, ((signed) base < 0) ? (base/2) : base); + if ((signed) base < 0) { + uint64_t q = *n; + /* + * First transformation: + * n = (base/2)*q + r + * = ((base/2)*2)*(q/2) + ((q&1) ? (base/2) : 0) + r + * Since r < (base/2), r + (base/2) < base. + * With q1 = (q/2) and r1 = r + ((q&1) ? (base/2) : 0) + * n = ((base/2)*2)*q1 + r1 with r1 < base. + */ + if (q & 1) + r += base/2; + q >>= 1; + /* + * Second transformation. ((base/2)*2) could have lost the + * last bit. + * n = ((base/2)*2)*q1 + r1 + * = base*q1 - ((base&1) ? q1 : 0) + r1 + */ + if (base & 1) { + int64_t rx = r - q; + /* + * base is >= 2^31. The worst case for the while + * loop is n=2^64-1 base=2^31+1. That gives a + * maximum for q=(2^64-1)/2^31 = 0x1ffffffff. Since + * base >= 2^31 the loop is finished after a maximum + * of three iterations. + */ + while (rx < 0) { + rx += base; + q--; + } + r = rx; + } + *n = q; + } + return r; +} + +#else /* MARCH_G5 */ + +uint32_t __div64_32(uint64_t *n, uint32_t base) +{ + register uint32_t reg2 asm("2"); + register uint32_t reg3 asm("3"); + uint32_t *words = (uint32_t *) n; + + reg2 = 0UL; + reg3 = words[0]; + asm volatile( + " dlr %0,%2\n" + : "+d" (reg2), "+d" (reg3) : "d" (base) : "cc" ); + words[0] = reg3; + reg3 = words[1]; + asm volatile( + " dlr %0,%2\n" + : "+d" (reg2), "+d" (reg3) : "d" (base) : "cc" ); + words[1] = reg3; + return reg2; +} + +#endif /* MARCH_G5 */ + +EXPORT_SYMBOL(__div64_32); diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c index b9b7958a226a..8d76403fcf89 100644 --- a/arch/s390/lib/spinlock.c +++ b/arch/s390/lib/spinlock.c @@ -24,57 +24,76 @@ static int __init spin_retry_setup(char *str) } __setup("spin_retry=", spin_retry_setup); -static inline void -_diag44(void) +static inline void _raw_yield(void) { -#ifdef CONFIG_64BIT if (MACHINE_HAS_DIAG44) -#endif asm volatile("diag 0,0,0x44"); } -void -_raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc) +static inline void _raw_yield_cpu(int cpu) +{ + if (MACHINE_HAS_DIAG9C) + asm volatile("diag %0,0,0x9c" + : : "d" (__cpu_logical_map[cpu])); + else + _raw_yield(); +} + +void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc) { int count = spin_retry; + unsigned int cpu = ~smp_processor_id(); while (1) { if (count-- <= 0) { - _diag44(); + unsigned int owner = lp->owner_cpu; + if (owner != 0) + _raw_yield_cpu(~owner); count = spin_retry; } if (__raw_spin_is_locked(lp)) continue; - if (_raw_compare_and_swap(&lp->lock, 0, pc) == 0) + if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) { + lp->owner_pc = pc; return; + } } } EXPORT_SYMBOL(_raw_spin_lock_wait); -int -_raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc) +int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc) { - int count = spin_retry; + unsigned int cpu = ~smp_processor_id(); + int count; - while (count-- > 0) { + for (count = spin_retry; count > 0; count--) { if (__raw_spin_is_locked(lp)) continue; - if (_raw_compare_and_swap(&lp->lock, 0, pc) == 0) + if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) { + lp->owner_pc = pc; return 1; + } } return 0; } EXPORT_SYMBOL(_raw_spin_trylock_retry); -void -_raw_read_lock_wait(raw_rwlock_t *rw) +void _raw_spin_relax(raw_spinlock_t *lock) +{ + unsigned int cpu = lock->owner_cpu; + if (cpu != 0) + _raw_yield_cpu(~cpu); +} +EXPORT_SYMBOL(_raw_spin_relax); + +void _raw_read_lock_wait(raw_rwlock_t *rw) { unsigned int old; int count = spin_retry; while (1) { if (count-- <= 0) { - _diag44(); + _raw_yield(); count = spin_retry; } if (!__raw_read_can_lock(rw)) @@ -86,8 +105,7 @@ _raw_read_lock_wait(raw_rwlock_t *rw) } EXPORT_SYMBOL(_raw_read_lock_wait); -int -_raw_read_trylock_retry(raw_rwlock_t *rw) +int _raw_read_trylock_retry(raw_rwlock_t *rw) { unsigned int old; int count = spin_retry; @@ -103,14 +121,13 @@ _raw_read_trylock_retry(raw_rwlock_t *rw) } EXPORT_SYMBOL(_raw_read_trylock_retry); -void -_raw_write_lock_wait(raw_rwlock_t *rw) +void _raw_write_lock_wait(raw_rwlock_t *rw) { int count = spin_retry; while (1) { if (count-- <= 0) { - _diag44(); + _raw_yield(); count = spin_retry; } if (!__raw_write_can_lock(rw)) @@ -121,8 +138,7 @@ _raw_write_lock_wait(raw_rwlock_t *rw) } EXPORT_SYMBOL(_raw_write_lock_wait); -int -_raw_write_trylock_retry(raw_rwlock_t *rw) +int _raw_write_trylock_retry(raw_rwlock_t *rw) { int count = spin_retry; diff --git a/arch/s390/lib/uaccess.S b/arch/s390/lib/uaccess.S deleted file mode 100644 index 837275284d9f..000000000000 --- a/arch/s390/lib/uaccess.S +++ /dev/null @@ -1,211 +0,0 @@ -/* - * arch/s390/lib/uaccess.S - * __copy_{from|to}_user functions. - * - * s390 - * Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com) - * - * These functions have standard call interface - */ - -#include <linux/errno.h> -#include <asm/lowcore.h> -#include <asm/asm-offsets.h> - - .text - .align 4 - .globl __copy_from_user_asm - # %r2 = to, %r3 = n, %r4 = from -__copy_from_user_asm: - slr %r0,%r0 -0: mvcp 0(%r3,%r2),0(%r4),%r0 - jnz 1f - slr %r2,%r2 - br %r14 -1: la %r2,256(%r2) - la %r4,256(%r4) - ahi %r3,-256 -2: mvcp 0(%r3,%r2),0(%r4),%r0 - jnz 1b -3: slr %r2,%r2 - br %r14 -4: lhi %r0,-4096 - lr %r5,%r4 - slr %r5,%r0 - nr %r5,%r0 # %r5 = (%r4 + 4096) & -4096 - slr %r5,%r4 # %r5 = #bytes to next user page boundary - clr %r3,%r5 # copy crosses next page boundary ? - jnh 6f # no, the current page faulted - # move with the reduced length which is < 256 -5: mvcp 0(%r5,%r2),0(%r4),%r0 - slr %r3,%r5 -6: lr %r2,%r3 - br %r14 - .section __ex_table,"a" - .long 0b,4b - .long 2b,4b - .long 5b,6b - .previous - - .align 4 - .text - .globl __copy_to_user_asm - # %r2 = from, %r3 = n, %r4 = to -__copy_to_user_asm: - slr %r0,%r0 -0: mvcs 0(%r3,%r4),0(%r2),%r0 - jnz 1f - slr %r2,%r2 - br %r14 -1: la %r2,256(%r2) - la %r4,256(%r4) - ahi %r3,-256 -2: mvcs 0(%r3,%r4),0(%r2),%r0 - jnz 1b -3: slr %r2,%r2 - br %r14 -4: lhi %r0,-4096 - lr %r5,%r4 - slr %r5,%r0 - nr %r5,%r0 # %r5 = (%r4 + 4096) & -4096 - slr %r5,%r4 # %r5 = #bytes to next user page boundary - clr %r3,%r5 # copy crosses next page boundary ? - jnh 6f # no, the current page faulted - # move with the reduced length which is < 256 -5: mvcs 0(%r5,%r4),0(%r2),%r0 - slr %r3,%r5 -6: lr %r2,%r3 - br %r14 - .section __ex_table,"a" - .long 0b,4b - .long 2b,4b - .long 5b,6b - .previous - - .align 4 - .text - .globl __copy_in_user_asm - # %r2 = from, %r3 = n, %r4 = to -__copy_in_user_asm: - ahi %r3,-1 - jo 6f - sacf 256 - bras %r1,4f -0: ahi %r3,257 -1: mvc 0(1,%r4),0(%r2) - la %r2,1(%r2) - la %r4,1(%r4) - ahi %r3,-1 - jnz 1b -2: lr %r2,%r3 - br %r14 -3: mvc 0(256,%r4),0(%r2) - la %r2,256(%r2) - la %r4,256(%r4) -4: ahi %r3,-256 - jnm 3b -5: ex %r3,4(%r1) - sacf 0 -6: slr %r2,%r2 - br %r14 - .section __ex_table,"a" - .long 1b,2b - .long 3b,0b - .long 5b,0b - .previous - - .align 4 - .text - .globl __clear_user_asm - # %r2 = to, %r3 = n -__clear_user_asm: - bras %r5,0f - .long empty_zero_page -0: l %r5,0(%r5) - slr %r0,%r0 -1: mvcs 0(%r3,%r2),0(%r5),%r0 - jnz 2f - slr %r2,%r2 - br %r14 -2: la %r2,256(%r2) - ahi %r3,-256 -3: mvcs 0(%r3,%r2),0(%r5),%r0 - jnz 2b -4: slr %r2,%r2 - br %r14 -5: lhi %r0,-4096 - lr %r4,%r2 - slr %r4,%r0 - nr %r4,%r0 # %r4 = (%r2 + 4096) & -4096 - slr %r4,%r2 # %r4 = #bytes to next user page boundary - clr %r3,%r4 # clear crosses next page boundary ? - jnh 7f # no, the current page faulted - # clear with the reduced length which is < 256 -6: mvcs 0(%r4,%r2),0(%r5),%r0 - slr %r3,%r4 -7: lr %r2,%r3 - br %r14 - .section __ex_table,"a" - .long 1b,5b - .long 3b,5b - .long 6b,7b - .previous - - .align 4 - .text - .globl __strncpy_from_user_asm - # %r2 = count, %r3 = dst, %r4 = src -__strncpy_from_user_asm: - lhi %r0,0 - lr %r1,%r4 - la %r4,0(%r4) # clear high order bit from %r4 - la %r2,0(%r2,%r4) # %r2 points to first byte after string - sacf 256 -0: srst %r2,%r1 - jo 0b - sacf 0 - lr %r1,%r2 - jh 1f # \0 found in string ? - ahi %r1,1 # include \0 in copy -1: slr %r1,%r4 # %r1 = copy length (without \0) - slr %r2,%r4 # %r2 = return length (including \0) -2: mvcp 0(%r1,%r3),0(%r4),%r0 - jnz 3f - br %r14 -3: la %r3,256(%r3) - la %r4,256(%r4) - ahi %r1,-256 - mvcp 0(%r1,%r3),0(%r4),%r0 - jnz 3b - br %r14 -4: sacf 0 - lhi %r2,-EFAULT - br %r14 - .section __ex_table,"a" - .long 0b,4b - .previous - - .align 4 - .text - .globl __strnlen_user_asm - # %r2 = count, %r3 = src -__strnlen_user_asm: - lhi %r0,0 - lr %r1,%r3 - la %r3,0(%r3) # clear high order bit from %r4 - la %r2,0(%r2,%r3) # %r2 points to first byte after string - sacf 256 -0: srst %r2,%r1 - jo 0b - sacf 0 - ahi %r2,1 # strnlen_user result includes the \0 - # or return count+1 if \0 not found - slr %r2,%r3 - br %r14 -2: sacf 0 - slr %r2,%r2 # return 0 on exception - br %r14 - .section __ex_table,"a" - .long 0b,2b - .previous diff --git a/arch/s390/lib/uaccess64.S b/arch/s390/lib/uaccess64.S deleted file mode 100644 index 1f755be22f92..000000000000 --- a/arch/s390/lib/uaccess64.S +++ /dev/null @@ -1,207 +0,0 @@ -/* - * arch/s390x/lib/uaccess.S - * __copy_{from|to}_user functions. - * - * s390 - * Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com) - * - * These functions have standard call interface - */ - -#include <linux/errno.h> -#include <asm/lowcore.h> -#include <asm/asm-offsets.h> - - .text - .align 4 - .globl __copy_from_user_asm - # %r2 = to, %r3 = n, %r4 = from -__copy_from_user_asm: - slgr %r0,%r0 -0: mvcp 0(%r3,%r2),0(%r4),%r0 - jnz 1f - slgr %r2,%r2 - br %r14 -1: la %r2,256(%r2) - la %r4,256(%r4) - aghi %r3,-256 -2: mvcp 0(%r3,%r2),0(%r4),%r0 - jnz 1b -3: slgr %r2,%r2 - br %r14 -4: lghi %r0,-4096 - lgr %r5,%r4 - slgr %r5,%r0 - ngr %r5,%r0 # %r5 = (%r4 + 4096) & -4096 - slgr %r5,%r4 # %r5 = #bytes to next user page boundary - clgr %r3,%r5 # copy crosses next page boundary ? - jnh 6f # no, the current page faulted - # move with the reduced length which is < 256 -5: mvcp 0(%r5,%r2),0(%r4),%r0 - slgr %r3,%r5 -6: lgr %r2,%r3 - br %r14 - .section __ex_table,"a" - .quad 0b,4b - .quad 2b,4b - .quad 5b,6b - .previous - - .align 4 - .text - .globl __copy_to_user_asm - # %r2 = from, %r3 = n, %r4 = to -__copy_to_user_asm: - slgr %r0,%r0 -0: mvcs 0(%r3,%r4),0(%r2),%r0 - jnz 1f - slgr %r2,%r2 - br %r14 -1: la %r2,256(%r2) - la %r4,256(%r4) - aghi %r3,-256 -2: mvcs 0(%r3,%r4),0(%r2),%r0 - jnz 1b -3: slgr %r2,%r2 - br %r14 -4: lghi %r0,-4096 - lgr %r5,%r4 - slgr %r5,%r0 - ngr %r5,%r0 # %r5 = (%r4 + 4096) & -4096 - slgr %r5,%r4 # %r5 = #bytes to next user page boundary - clgr %r3,%r5 # copy crosses next page boundary ? - jnh 6f # no, the current page faulted - # move with the reduced length which is < 256 -5: mvcs 0(%r5,%r4),0(%r2),%r0 - slgr %r3,%r5 -6: lgr %r2,%r3 - br %r14 - .section __ex_table,"a" - .quad 0b,4b - .quad 2b,4b - .quad 5b,6b - .previous - - .align 4 - .text - .globl __copy_in_user_asm - # %r2 = from, %r3 = n, %r4 = to -__copy_in_user_asm: - aghi %r3,-1 - jo 6f - sacf 256 - bras %r1,4f -0: aghi %r3,257 -1: mvc 0(1,%r4),0(%r2) - la %r2,1(%r2) - la %r4,1(%r4) - aghi %r3,-1 - jnz 1b -2: lgr %r2,%r3 - br %r14 -3: mvc 0(256,%r4),0(%r2) - la %r2,256(%r2) - la %r4,256(%r4) -4: aghi %r3,-256 - jnm 3b -5: ex %r3,4(%r1) - sacf 0 -6: slgr %r2,%r2 - br 14 - .section __ex_table,"a" - .quad 1b,2b - .quad 3b,0b - .quad 5b,0b - .previous - - .align 4 - .text - .globl __clear_user_asm - # %r2 = to, %r3 = n -__clear_user_asm: - slgr %r0,%r0 - larl %r5,empty_zero_page -1: mvcs 0(%r3,%r2),0(%r5),%r0 - jnz 2f - slgr %r2,%r2 - br %r14 -2: la %r2,256(%r2) - aghi %r3,-256 -3: mvcs 0(%r3,%r2),0(%r5),%r0 - jnz 2b -4: slgr %r2,%r2 - br %r14 -5: lghi %r0,-4096 - lgr %r4,%r2 - slgr %r4,%r0 - ngr %r4,%r0 # %r4 = (%r2 + 4096) & -4096 - slgr %r4,%r2 # %r4 = #bytes to next user page boundary - clgr %r3,%r4 # clear crosses next page boundary ? - jnh 7f # no, the current page faulted - # clear with the reduced length which is < 256 -6: mvcs 0(%r4,%r2),0(%r5),%r0 - slgr %r3,%r4 -7: lgr %r2,%r3 - br %r14 - .section __ex_table,"a" - .quad 1b,5b - .quad 3b,5b - .quad 6b,7b - .previous - - .align 4 - .text - .globl __strncpy_from_user_asm - # %r2 = count, %r3 = dst, %r4 = src -__strncpy_from_user_asm: - lghi %r0,0 - lgr %r1,%r4 - la %r2,0(%r2,%r4) # %r2 points to first byte after string - sacf 256 -0: srst %r2,%r1 - jo 0b - sacf 0 - lgr %r1,%r2 - jh 1f # \0 found in string ? - aghi %r1,1 # include \0 in copy -1: slgr %r1,%r4 # %r1 = copy length (without \0) - slgr %r2,%r4 # %r2 = return length (including \0) -2: mvcp 0(%r1,%r3),0(%r4),%r0 - jnz 3f - br %r14 -3: la %r3,256(%r3) - la %r4,256(%r4) - aghi %r1,-256 - mvcp 0(%r1,%r3),0(%r4),%r0 - jnz 3b - br %r14 -4: sacf 0 - lghi %r2,-EFAULT - br %r14 - .section __ex_table,"a" - .quad 0b,4b - .previous - - .align 4 - .text - .globl __strnlen_user_asm - # %r2 = count, %r3 = src -__strnlen_user_asm: - lghi %r0,0 - lgr %r1,%r3 - la %r2,0(%r2,%r3) # %r2 points to first byte after string - sacf 256 -0: srst %r2,%r1 - jo 0b - sacf 0 - aghi %r2,1 # strnlen_user result includes the \0 - # or return count+1 if \0 not found - slgr %r2,%r3 - br %r14 -2: sacf 0 - slgr %r2,%r2 # return 0 on exception - br %r14 - .section __ex_table,"a" - .quad 0b,2b - .previous diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c new file mode 100644 index 000000000000..121b2935a422 --- /dev/null +++ b/arch/s390/lib/uaccess_mvcos.c @@ -0,0 +1,166 @@ +/* + * arch/s390/lib/uaccess_mvcos.c + * + * Optimized user space space access functions based on mvcos. + * + * Copyright (C) IBM Corp. 2006 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * Gerald Schaefer (gerald.schaefer@de.ibm.com) + */ + +#include <linux/errno.h> +#include <linux/mm.h> +#include <asm/uaccess.h> +#include <asm/futex.h> + +#ifndef __s390x__ +#define AHI "ahi" +#define ALR "alr" +#define CLR "clr" +#define LHI "lhi" +#define SLR "slr" +#else +#define AHI "aghi" +#define ALR "algr" +#define CLR "clgr" +#define LHI "lghi" +#define SLR "slgr" +#endif + +size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) +{ + register unsigned long reg0 asm("0") = 0x81UL; + unsigned long tmp1, tmp2; + + tmp1 = -4096UL; + asm volatile( + "0: .insn ss,0xc80000000000,0(%0,%2),0(%1),0\n" + " jz 7f\n" + "1:"ALR" %0,%3\n" + " "SLR" %1,%3\n" + " "SLR" %2,%3\n" + " j 0b\n" + "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */ + " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */ + " "SLR" %4,%1\n" + " "CLR" %0,%4\n" /* copy crosses next page boundary? */ + " jnh 4f\n" + "3: .insn ss,0xc80000000000,0(%4,%2),0(%1),0\n" + " "SLR" %0,%4\n" + " "ALR" %2,%4\n" + "4:"LHI" %4,-1\n" + " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */ + " bras %3,6f\n" /* memset loop */ + " xc 0(1,%2),0(%2)\n" + "5: xc 0(256,%2),0(%2)\n" + " la %2,256(%2)\n" + "6:"AHI" %4,-256\n" + " jnm 5b\n" + " ex %4,0(%3)\n" + " j 8f\n" + "7:"SLR" %0,%0\n" + "8: \n" + EX_TABLE(0b,2b) EX_TABLE(3b,4b) + : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) + : "d" (reg0) : "cc", "memory"); + return size; +} + +size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) +{ + register unsigned long reg0 asm("0") = 0x810000UL; + unsigned long tmp1, tmp2; + + tmp1 = -4096UL; + asm volatile( + "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n" + " jz 4f\n" + "1:"ALR" %0,%3\n" + " "SLR" %1,%3\n" + " "SLR" %2,%3\n" + " j 0b\n" + "2: la %4,4095(%1)\n"/* %4 = ptr + 4095 */ + " nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */ + " "SLR" %4,%1\n" + " "CLR" %0,%4\n" /* copy crosses next page boundary? */ + " jnh 5f\n" + "3: .insn ss,0xc80000000000,0(%4,%1),0(%2),0\n" + " "SLR" %0,%4\n" + " j 5f\n" + "4:"SLR" %0,%0\n" + "5: \n" + EX_TABLE(0b,2b) EX_TABLE(3b,5b) + : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) + : "d" (reg0) : "cc", "memory"); + return size; +} + +size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from) +{ + register unsigned long reg0 asm("0") = 0x810081UL; + unsigned long tmp1, tmp2; + + tmp1 = -4096UL; + /* FIXME: copy with reduced length. */ + asm volatile( + "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n" + " jz 2f\n" + "1:"ALR" %0,%3\n" + " "SLR" %1,%3\n" + " "SLR" %2,%3\n" + " j 0b\n" + "2:"SLR" %0,%0\n" + "3: \n" + EX_TABLE(0b,3b) + : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2) + : "d" (reg0) : "cc", "memory"); + return size; +} + +size_t clear_user_mvcos(size_t size, void __user *to) +{ + register unsigned long reg0 asm("0") = 0x810000UL; + unsigned long tmp1, tmp2; + + tmp1 = -4096UL; + asm volatile( + "0: .insn ss,0xc80000000000,0(%0,%1),0(%4),0\n" + " jz 4f\n" + "1:"ALR" %0,%2\n" + " "SLR" %1,%2\n" + " j 0b\n" + "2: la %3,4095(%1)\n"/* %4 = to + 4095 */ + " nr %3,%2\n" /* %4 = (to + 4095) & -4096 */ + " "SLR" %3,%1\n" + " "CLR" %0,%3\n" /* copy crosses next page boundary? */ + " jnh 5f\n" + "3: .insn ss,0xc80000000000,0(%3,%1),0(%4),0\n" + " "SLR" %0,%3\n" + " j 5f\n" + "4:"SLR" %0,%0\n" + "5: \n" + EX_TABLE(0b,2b) EX_TABLE(3b,5b) + : "+a" (size), "+a" (to), "+a" (tmp1), "=a" (tmp2) + : "a" (empty_zero_page), "d" (reg0) : "cc", "memory"); + return size; +} + +extern size_t copy_from_user_std_small(size_t, const void __user *, void *); +extern size_t copy_to_user_std_small(size_t, void __user *, const void *); +extern size_t strnlen_user_std(size_t, const char __user *); +extern size_t strncpy_from_user_std(size_t, const char __user *, char *); +extern int futex_atomic_op(int, int __user *, int, int *); +extern int futex_atomic_cmpxchg(int __user *, int, int); + +struct uaccess_ops uaccess_mvcos = { + .copy_from_user = copy_from_user_mvcos, + .copy_from_user_small = copy_from_user_std_small, + .copy_to_user = copy_to_user_mvcos, + .copy_to_user_small = copy_to_user_std_small, + .copy_in_user = copy_in_user_mvcos, + .clear_user = clear_user_mvcos, + .strnlen_user = strnlen_user_std, + .strncpy_from_user = strncpy_from_user_std, + .futex_atomic_op = futex_atomic_op, + .futex_atomic_cmpxchg = futex_atomic_cmpxchg, +}; diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c new file mode 100644 index 000000000000..f44f0078b354 --- /dev/null +++ b/arch/s390/lib/uaccess_std.c @@ -0,0 +1,356 @@ +/* + * arch/s390/lib/uaccess_std.c + * + * Standard user space access functions based on mvcp/mvcs and doing + * interesting things in the secondary space mode. + * + * Copyright (C) IBM Corp. 2006 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), + * Gerald Schaefer (gerald.schaefer@de.ibm.com) + */ + +#include <linux/errno.h> +#include <linux/mm.h> +#include <asm/uaccess.h> +#include <asm/futex.h> + +#ifndef __s390x__ +#define AHI "ahi" +#define ALR "alr" +#define CLR "clr" +#define LHI "lhi" +#define SLR "slr" +#else +#define AHI "aghi" +#define ALR "algr" +#define CLR "clgr" +#define LHI "lghi" +#define SLR "slgr" +#endif + +size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) +{ + unsigned long tmp1, tmp2; + + tmp1 = -256UL; + asm volatile( + "0: mvcp 0(%0,%2),0(%1),%3\n" + " jz 8f\n" + "1:"ALR" %0,%3\n" + " la %1,256(%1)\n" + " la %2,256(%2)\n" + "2: mvcp 0(%0,%2),0(%1),%3\n" + " jnz 1b\n" + " j 8f\n" + "3: la %4,255(%1)\n" /* %4 = ptr + 255 */ + " "LHI" %3,-4096\n" + " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */ + " "SLR" %4,%1\n" + " "CLR" %0,%4\n" /* copy crosses next page boundary? */ + " jnh 5f\n" + "4: mvcp 0(%4,%2),0(%1),%3\n" + " "SLR" %0,%4\n" + " "ALR" %2,%4\n" + "5:"LHI" %4,-1\n" + " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */ + " bras %3,7f\n" /* memset loop */ + " xc 0(1,%2),0(%2)\n" + "6: xc 0(256,%2),0(%2)\n" + " la %2,256(%2)\n" + "7:"AHI" %4,-256\n" + " jnm 6b\n" + " ex %4,0(%3)\n" + " j 9f\n" + "8:"SLR" %0,%0\n" + "9: \n" + EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,5b) + : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) + : : "cc", "memory"); + return size; +} + +size_t copy_from_user_std_small(size_t size, const void __user *ptr, void *x) +{ + unsigned long tmp1, tmp2; + + tmp1 = 0UL; + asm volatile( + "0: mvcp 0(%0,%2),0(%1),%3\n" + " "SLR" %0,%0\n" + " j 5f\n" + "1: la %4,255(%1)\n" /* %4 = ptr + 255 */ + " "LHI" %3,-4096\n" + " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */ + " "SLR" %4,%1\n" + " "CLR" %0,%4\n" /* copy crosses next page boundary? */ + " jnh 5f\n" + "2: mvcp 0(%4,%2),0(%1),%3\n" + " "SLR" %0,%4\n" + " "ALR" %2,%4\n" + "3:"LHI" %4,-1\n" + " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */ + " bras %3,4f\n" + " xc 0(1,%2),0(%2)\n" + "4: ex %4,0(%3)\n" + "5:\n" + EX_TABLE(0b,1b) EX_TABLE(2b,3b) + : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) + : : "cc", "memory"); + return size; +} + +size_t copy_to_user_std(size_t size, void __user *ptr, const void *x) +{ + unsigned long tmp1, tmp2; + + tmp1 = -256UL; + asm volatile( + "0: mvcs 0(%0,%1),0(%2),%3\n" + " jz 5f\n" + "1:"ALR" %0,%3\n" + " la %1,256(%1)\n" + " la %2,256(%2)\n" + "2: mvcs 0(%0,%1),0(%2),%3\n" + " jnz 1b\n" + " j 5f\n" + "3: la %4,255(%1)\n" /* %4 = ptr + 255 */ + " "LHI" %3,-4096\n" + " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */ + " "SLR" %4,%1\n" + " "CLR" %0,%4\n" /* copy crosses next page boundary? */ + " jnh 6f\n" + "4: mvcs 0(%4,%1),0(%2),%3\n" + " "SLR" %0,%4\n" + " j 6f\n" + "5:"SLR" %0,%0\n" + "6: \n" + EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b) + : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) + : : "cc", "memory"); + return size; +} + +size_t copy_to_user_std_small(size_t size, void __user *ptr, const void *x) +{ + unsigned long tmp1, tmp2; + + tmp1 = 0UL; + asm volatile( + "0: mvcs 0(%0,%1),0(%2),%3\n" + " "SLR" %0,%0\n" + " j 3f\n" + "1: la %4,255(%1)\n" /* ptr + 255 */ + " "LHI" %3,-4096\n" + " nr %4,%3\n" /* (ptr + 255) & -4096UL */ + " "SLR" %4,%1\n" + " "CLR" %0,%4\n" /* copy crosses next page boundary? */ + " jnh 3f\n" + "2: mvcs 0(%4,%1),0(%2),%3\n" + " "SLR" %0,%4\n" + "3:\n" + EX_TABLE(0b,1b) EX_TABLE(2b,3b) + : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) + : : "cc", "memory"); + return size; +} + +size_t copy_in_user_std(size_t size, void __user *to, const void __user *from) +{ + unsigned long tmp1; + + asm volatile( + " "AHI" %0,-1\n" + " jo 5f\n" + " sacf 256\n" + " bras %3,3f\n" + "0:"AHI" %0,257\n" + "1: mvc 0(1,%1),0(%2)\n" + " la %1,1(%1)\n" + " la %2,1(%2)\n" + " "AHI" %0,-1\n" + " jnz 1b\n" + " j 5f\n" + "2: mvc 0(256,%1),0(%2)\n" + " la %1,256(%1)\n" + " la %2,256(%2)\n" + "3:"AHI" %0,-256\n" + " jnm 2b\n" + "4: ex %0,1b-0b(%3)\n" + " sacf 0\n" + "5: "SLR" %0,%0\n" + "6:\n" + EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b) + : "+a" (size), "+a" (to), "+a" (from), "=a" (tmp1) + : : "cc", "memory"); + return size; +} + +size_t clear_user_std(size_t size, void __user *to) +{ + unsigned long tmp1, tmp2; + + asm volatile( + " "AHI" %0,-1\n" + " jo 5f\n" + " sacf 256\n" + " bras %3,3f\n" + " xc 0(1,%1),0(%1)\n" + "0:"AHI" %0,257\n" + " la %2,255(%1)\n" /* %2 = ptr + 255 */ + " srl %2,12\n" + " sll %2,12\n" /* %2 = (ptr + 255) & -4096 */ + " "SLR" %2,%1\n" + " "CLR" %0,%2\n" /* clear crosses next page boundary? */ + " jnh 5f\n" + " "AHI" %2,-1\n" + "1: ex %2,0(%3)\n" + " "AHI" %2,1\n" + " "SLR" %0,%2\n" + " j 5f\n" + "2: xc 0(256,%1),0(%1)\n" + " la %1,256(%1)\n" + "3:"AHI" %0,-256\n" + " jnm 2b\n" + "4: ex %0,0(%3)\n" + " sacf 0\n" + "5: "SLR" %0,%0\n" + "6:\n" + EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b) + : "+a" (size), "+a" (to), "=a" (tmp1), "=a" (tmp2) + : : "cc", "memory"); + return size; +} + +size_t strnlen_user_std(size_t size, const char __user *src) +{ + register unsigned long reg0 asm("0") = 0UL; + unsigned long tmp1, tmp2; + + asm volatile( + " la %2,0(%1)\n" + " la %3,0(%0,%1)\n" + " "SLR" %0,%0\n" + " sacf 256\n" + "0: srst %3,%2\n" + " jo 0b\n" + " la %0,1(%3)\n" /* strnlen_user results includes \0 */ + " "SLR" %0,%1\n" + "1: sacf 0\n" + EX_TABLE(0b,1b) + : "+a" (size), "+a" (src), "=a" (tmp1), "=a" (tmp2) + : "d" (reg0) : "cc", "memory"); + return size; +} + +size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst) +{ + register unsigned long reg0 asm("0") = 0UL; + unsigned long tmp1, tmp2; + + asm volatile( + " la %3,0(%1)\n" + " la %4,0(%0,%1)\n" + " sacf 256\n" + "0: srst %4,%3\n" + " jo 0b\n" + " sacf 0\n" + " la %0,0(%4)\n" + " jh 1f\n" /* found \0 in string ? */ + " "AHI" %4,1\n" /* include \0 in copy */ + "1:"SLR" %0,%1\n" /* %0 = return length (without \0) */ + " "SLR" %4,%1\n" /* %4 = copy length (including \0) */ + "2: mvcp 0(%4,%2),0(%1),%5\n" + " jz 9f\n" + "3:"AHI" %4,-256\n" + " la %1,256(%1)\n" + " la %2,256(%2)\n" + "4: mvcp 0(%4,%2),0(%1),%5\n" + " jnz 3b\n" + " j 9f\n" + "7: sacf 0\n" + "8:"LHI" %0,%6\n" + "9:\n" + EX_TABLE(0b,7b) EX_TABLE(2b,8b) EX_TABLE(4b,8b) + : "+a" (size), "+a" (src), "+d" (dst), "=a" (tmp1), "=a" (tmp2) + : "d" (reg0), "K" (-EFAULT) : "cc", "memory"); + return size; +} + +#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \ + asm volatile( \ + " sacf 256\n" \ + "0: l %1,0(%6)\n" \ + "1:"insn \ + "2: cs %1,%2,0(%6)\n" \ + "3: jl 1b\n" \ + " lhi %0,0\n" \ + "4: sacf 0\n" \ + EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b) \ + : "=d" (ret), "=&d" (oldval), "=&d" (newval), \ + "=m" (*uaddr) \ + : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \ + "m" (*uaddr) : "cc"); + +int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old) +{ + int oldval = 0, newval, ret; + + inc_preempt_count(); + + switch (op) { + case FUTEX_OP_SET: + __futex_atomic_op("lr %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + case FUTEX_OP_ADD: + __futex_atomic_op("lr %2,%1\nar %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + case FUTEX_OP_OR: + __futex_atomic_op("lr %2,%1\nor %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + case FUTEX_OP_ANDN: + __futex_atomic_op("lr %2,%1\nnr %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + case FUTEX_OP_XOR: + __futex_atomic_op("lr %2,%1\nxr %2,%5\n", + ret, oldval, newval, uaddr, oparg); + break; + default: + ret = -ENOSYS; + } + dec_preempt_count(); + *old = oldval; + return ret; +} + +int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval) +{ + int ret; + + asm volatile( + " sacf 256\n" + " cs %1,%4,0(%5)\n" + "0: lr %0,%1\n" + "1: sacf 0\n" + EX_TABLE(0b,1b) + : "=d" (ret), "+d" (oldval), "=m" (*uaddr) + : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr) + : "cc", "memory" ); + return ret; +} + +struct uaccess_ops uaccess_std = { + .copy_from_user = copy_from_user_std, + .copy_from_user_small = copy_from_user_std_small, + .copy_to_user = copy_to_user_std, + .copy_to_user_small = copy_to_user_std_small, + .copy_in_user = copy_in_user_std, + .clear_user = clear_user_std, + .strnlen_user = strnlen_user_std, + .strncpy_from_user = strncpy_from_user_std, + .futex_atomic_op = futex_atomic_op, + .futex_atomic_cmpxchg = futex_atomic_cmpxchg, +}; diff --git a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c index b4957c84e4d6..6b9aec5a2c18 100644 --- a/arch/s390/math-emu/math.c +++ b/arch/s390/math-emu/math.c @@ -1564,52 +1564,52 @@ static int emu_tceb (struct pt_regs *regs, int rx, long val) { } static inline void emu_load_regd(int reg) { - if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ + if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ return; - asm volatile ( /* load reg from fp_regs.fprs[reg] */ - " bras 1,0f\n" - " ld 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (reg<<4),"a" (¤t->thread.fp_regs.fprs[reg].d) - : "1" ); + asm volatile( /* load reg from fp_regs.fprs[reg] */ + " bras 1,0f\n" + " ld 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (reg<<4),"a" (¤t->thread.fp_regs.fprs[reg].d) + : "1"); } static inline void emu_load_rege(int reg) { - if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ + if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ return; - asm volatile ( /* load reg from fp_regs.fprs[reg] */ - " bras 1,0f\n" - " le 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f) - : "1" ); + asm volatile( /* load reg from fp_regs.fprs[reg] */ + " bras 1,0f\n" + " le 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f) + : "1"); } static inline void emu_store_regd(int reg) { - if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ + if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ return; - asm volatile ( /* store reg to fp_regs.fprs[reg] */ - " bras 1,0f\n" - " std 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].d) - : "1" ); + asm volatile( /* store reg to fp_regs.fprs[reg] */ + " bras 1,0f\n" + " std 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].d) + : "1"); } static inline void emu_store_rege(int reg) { - if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ + if ((reg&9) != 0) /* test if reg in {0,2,4,6} */ return; - asm volatile ( /* store reg to fp_regs.fprs[reg] */ - " bras 1,0f\n" - " ste 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f) - : "1" ); + asm volatile( /* store reg to fp_regs.fprs[reg] */ + " bras 1,0f\n" + " ste 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (reg<<4), "a" (¤t->thread.fp_regs.fprs[reg].f) + : "1"); } int math_emu_b3(__u8 *opcode, struct pt_regs * regs) { @@ -2089,23 +2089,22 @@ int math_emu_ldr(__u8 *opcode) { if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */ /* we got an exception therfore ry can't be in {0,2,4,6} */ - __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */ - " bras 1,0f\n" - " ld 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (opc & 0xf0), - "a" (&fp_regs->fprs[opc & 0xf].d) - : "1" ); + asm volatile( /* load rx from fp_regs.fprs[ry] */ + " bras 1,0f\n" + " ld 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (opc & 0xf0), "a" (&fp_regs->fprs[opc & 0xf].d) + : "1"); } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */ - __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */ - " bras 1,0f\n" - " std 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" ((opc & 0xf) << 4), - "a" (&fp_regs->fprs[(opc & 0xf0)>>4].d) - : "1" ); + asm volatile ( /* store ry to fp_regs.fprs[rx] */ + " bras 1,0f\n" + " std 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" ((opc & 0xf) << 4), + "a" (&fp_regs->fprs[(opc & 0xf0)>>4].d) + : "1"); } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */ fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf]; return 0; @@ -2120,23 +2119,22 @@ int math_emu_ler(__u8 *opcode) { if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */ /* we got an exception therfore ry can't be in {0,2,4,6} */ - __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */ - " bras 1,0f\n" - " le 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" (opc & 0xf0), - "a" (&fp_regs->fprs[opc & 0xf].f) - : "1" ); + asm volatile( /* load rx from fp_regs.fprs[ry] */ + " bras 1,0f\n" + " le 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" (opc & 0xf0), "a" (&fp_regs->fprs[opc & 0xf].f) + : "1"); } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */ - __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */ - " bras 1,0f\n" - " ste 0,0(%1)\n" - "0: ex %0,0(1)" - : /* no output */ - : "a" ((opc & 0xf) << 4), - "a" (&fp_regs->fprs[(opc & 0xf0) >> 4].f) - : "1" ); + asm volatile( /* store ry to fp_regs.fprs[rx] */ + " bras 1,0f\n" + " ste 0,0(%1)\n" + "0: ex %0,0(1)" + : /* no output */ + : "a" ((opc & 0xf) << 4), + "a" (&fp_regs->fprs[(opc & 0xf0) >> 4].f) + : "1"); } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */ fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf]; return 0; diff --git a/arch/s390/math-emu/sfp-util.h b/arch/s390/math-emu/sfp-util.h index ab556b600f73..5b6ca4570ea4 100644 --- a/arch/s390/math-emu/sfp-util.h +++ b/arch/s390/math-emu/sfp-util.h @@ -4,48 +4,51 @@ #include <asm/byteorder.h> #define add_ssaaaa(sh, sl, ah, al, bh, bl) ({ \ - unsigned int __sh = (ah); \ - unsigned int __sl = (al); \ - __asm__ (" alr %1,%3\n" \ - " brc 12,0f\n" \ - " ahi %0,1\n" \ - "0: alr %0,%2" \ - : "+&d" (__sh), "+d" (__sl) \ - : "d" (bh), "d" (bl) : "cc" ); \ - (sh) = __sh; \ - (sl) = __sl; \ + unsigned int __sh = (ah); \ + unsigned int __sl = (al); \ + asm volatile( \ + " alr %1,%3\n" \ + " brc 12,0f\n" \ + " ahi %0,1\n" \ + "0: alr %0,%2" \ + : "+&d" (__sh), "+d" (__sl) \ + : "d" (bh), "d" (bl) : "cc"); \ + (sh) = __sh; \ + (sl) = __sl; \ }) #define sub_ddmmss(sh, sl, ah, al, bh, bl) ({ \ - unsigned int __sh = (ah); \ - unsigned int __sl = (al); \ - __asm__ (" slr %1,%3\n" \ - " brc 3,0f\n" \ - " ahi %0,-1\n" \ - "0: slr %0,%2" \ - : "+&d" (__sh), "+d" (__sl) \ - : "d" (bh), "d" (bl) : "cc" ); \ - (sh) = __sh; \ - (sl) = __sl; \ + unsigned int __sh = (ah); \ + unsigned int __sl = (al); \ + asm volatile( \ + " slr %1,%3\n" \ + " brc 3,0f\n" \ + " ahi %0,-1\n" \ + "0: slr %0,%2" \ + : "+&d" (__sh), "+d" (__sl) \ + : "d" (bh), "d" (bl) : "cc"); \ + (sh) = __sh; \ + (sl) = __sl; \ }) /* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */ #define umul_ppmm(wh, wl, u, v) ({ \ - unsigned int __wh = u; \ - unsigned int __wl = v; \ - __asm__ (" ltr 1,%0\n" \ - " mr 0,%1\n" \ - " jnm 0f\n" \ - " alr 0,%1\n" \ - "0: ltr %1,%1\n" \ - " jnm 1f\n" \ - " alr 0,%0\n" \ - "1: lr %0,0\n" \ - " lr %1,1\n" \ - : "+d" (__wh), "+d" (__wl) \ - : : "0", "1", "cc" ); \ - wh = __wh; \ - wl = __wl; \ + unsigned int __wh = u; \ + unsigned int __wl = v; \ + asm volatile( \ + " ltr 1,%0\n" \ + " mr 0,%1\n" \ + " jnm 0f\n" \ + " alr 0,%1\n" \ + "0: ltr %1,%1\n" \ + " jnm 1f\n" \ + " alr 0,%0\n" \ + "1: lr %0,0\n" \ + " lr %1,1\n" \ + : "+d" (__wh), "+d" (__wl) \ + : : "0", "1", "cc"); \ + wh = __wh; \ + wl = __wl; \ }) #define udiv_qrnnd(q, r, n1, n0, d) \ diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index ceea51cff03b..607f50ead1fd 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -15,6 +15,8 @@ #include <linux/sched.h> #include <linux/sysctl.h> #include <linux/ctype.h> +#include <linux/swap.h> +#include <linux/kthread.h> #include <asm/pgalloc.h> #include <asm/uaccess.h> @@ -34,18 +36,18 @@ struct cmm_page_array { unsigned long pages[CMM_NR_PAGES]; }; -static long cmm_pages = 0; -static long cmm_timed_pages = 0; -static volatile long cmm_pages_target = 0; -static volatile long cmm_timed_pages_target = 0; -static long cmm_timeout_pages = 0; -static long cmm_timeout_seconds = 0; +static long cmm_pages; +static long cmm_timed_pages; +static volatile long cmm_pages_target; +static volatile long cmm_timed_pages_target; +static long cmm_timeout_pages; +static long cmm_timeout_seconds; -static struct cmm_page_array *cmm_page_list = NULL; -static struct cmm_page_array *cmm_timed_page_list = NULL; +static struct cmm_page_array *cmm_page_list; +static struct cmm_page_array *cmm_timed_page_list; +static DEFINE_SPINLOCK(cmm_lock); -static unsigned long cmm_thread_active = 0; -static struct work_struct cmm_thread_starter; +static struct task_struct *cmm_thread_ptr; static wait_queue_head_t cmm_thread_wait; static struct timer_list cmm_timer; @@ -53,87 +55,100 @@ static void cmm_timer_fn(unsigned long); static void cmm_set_timer(void); static long -cmm_strtoul(const char *cp, char **endp) +cmm_alloc_pages(long nr, long *counter, struct cmm_page_array **list) { - unsigned int base = 10; - - if (*cp == '0') { - base = 8; - cp++; - if ((*cp == 'x' || *cp == 'X') && isxdigit(cp[1])) { - base = 16; - cp++; - } - } - return simple_strtoul(cp, endp, base); -} - -static long -cmm_alloc_pages(long pages, long *counter, struct cmm_page_array **list) -{ - struct cmm_page_array *pa; - unsigned long page; + struct cmm_page_array *pa, *npa; + unsigned long addr; - pa = *list; - while (pages) { - page = __get_free_page(GFP_NOIO); - if (!page) + while (nr) { + addr = __get_free_page(GFP_NOIO); + if (!addr) break; + spin_lock(&cmm_lock); + pa = *list; if (!pa || pa->index >= CMM_NR_PAGES) { /* Need a new page for the page list. */ - pa = (struct cmm_page_array *) + spin_unlock(&cmm_lock); + npa = (struct cmm_page_array *) __get_free_page(GFP_NOIO); - if (!pa) { - free_page(page); + if (!npa) { + free_page(addr); break; } - pa->next = *list; - pa->index = 0; - *list = pa; + spin_lock(&cmm_lock); + pa = *list; + if (!pa || pa->index >= CMM_NR_PAGES) { + npa->next = pa; + npa->index = 0; + pa = npa; + *list = pa; + } else + free_page((unsigned long) npa); } - diag10(page); - pa->pages[pa->index++] = page; + diag10(addr); + pa->pages[pa->index++] = addr; (*counter)++; - pages--; + spin_unlock(&cmm_lock); + nr--; } - return pages; + return nr; } -static void -cmm_free_pages(long pages, long *counter, struct cmm_page_array **list) +static long +cmm_free_pages(long nr, long *counter, struct cmm_page_array **list) { struct cmm_page_array *pa; - unsigned long page; + unsigned long addr; + spin_lock(&cmm_lock); pa = *list; - while (pages) { + while (nr) { if (!pa || pa->index <= 0) break; - page = pa->pages[--pa->index]; + addr = pa->pages[--pa->index]; if (pa->index == 0) { pa = pa->next; free_page((unsigned long) *list); *list = pa; } - free_page(page); + free_page(addr); (*counter)--; - pages--; + nr--; } + spin_unlock(&cmm_lock); + return nr; +} + +static int cmm_oom_notify(struct notifier_block *self, + unsigned long dummy, void *parm) +{ + unsigned long *freed = parm; + long nr = 256; + + nr = cmm_free_pages(nr, &cmm_timed_pages, &cmm_timed_page_list); + if (nr > 0) + nr = cmm_free_pages(nr, &cmm_pages, &cmm_page_list); + cmm_pages_target = cmm_pages; + cmm_timed_pages_target = cmm_timed_pages; + *freed += 256 - nr; + return NOTIFY_OK; } +static struct notifier_block cmm_oom_nb = { + .notifier_call = cmm_oom_notify +}; + static int cmm_thread(void *dummy) { int rc; - daemonize("cmmthread"); while (1) { rc = wait_event_interruptible(cmm_thread_wait, (cmm_pages != cmm_pages_target || - cmm_timed_pages != cmm_timed_pages_target)); - if (rc == -ERESTARTSYS) { - /* Got kill signal. End thread. */ - clear_bit(0, &cmm_thread_active); + cmm_timed_pages != cmm_timed_pages_target || + kthread_should_stop())); + if (kthread_should_stop() || rc == -ERESTARTSYS) { cmm_pages_target = cmm_pages; cmm_timed_pages_target = cmm_timed_pages; break; @@ -159,16 +174,8 @@ cmm_thread(void *dummy) } static void -cmm_start_thread(void) -{ - kernel_thread(cmm_thread, NULL, 0); -} - -static void cmm_kick_thread(void) { - if (!test_and_set_bit(0, &cmm_thread_active)) - schedule_work(&cmm_thread_starter); wake_up(&cmm_thread_wait); } @@ -193,21 +200,21 @@ cmm_set_timer(void) static void cmm_timer_fn(unsigned long ignored) { - long pages; + long nr; - pages = cmm_timed_pages_target - cmm_timeout_pages; - if (pages < 0) + nr = cmm_timed_pages_target - cmm_timeout_pages; + if (nr < 0) cmm_timed_pages_target = 0; else - cmm_timed_pages_target = pages; + cmm_timed_pages_target = nr; cmm_kick_thread(); cmm_set_timer(); } void -cmm_set_pages(long pages) +cmm_set_pages(long nr) { - cmm_pages_target = pages; + cmm_pages_target = nr; cmm_kick_thread(); } @@ -218,9 +225,9 @@ cmm_get_pages(void) } void -cmm_add_timed_pages(long pages) +cmm_add_timed_pages(long nr) { - cmm_timed_pages_target += pages; + cmm_timed_pages_target += nr; cmm_kick_thread(); } @@ -231,9 +238,9 @@ cmm_get_timed_pages(void) } void -cmm_set_timeout(long pages, long seconds) +cmm_set_timeout(long nr, long seconds) { - cmm_timeout_pages = pages; + cmm_timeout_pages = nr; cmm_timeout_seconds = seconds; cmm_set_timer(); } @@ -261,7 +268,7 @@ cmm_pages_handler(ctl_table *ctl, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { char buf[16], *p; - long pages; + long nr; int len; if (!*lenp || (*ppos && !write)) { @@ -276,17 +283,17 @@ cmm_pages_handler(ctl_table *ctl, int write, struct file *filp, return -EFAULT; buf[sizeof(buf) - 1] = '\0'; cmm_skip_blanks(buf, &p); - pages = cmm_strtoul(p, &p); + nr = simple_strtoul(p, &p, 0); if (ctl == &cmm_table[0]) - cmm_set_pages(pages); + cmm_set_pages(nr); else - cmm_add_timed_pages(pages); + cmm_add_timed_pages(nr); } else { if (ctl == &cmm_table[0]) - pages = cmm_get_pages(); + nr = cmm_get_pages(); else - pages = cmm_get_timed_pages(); - len = sprintf(buf, "%ld\n", pages); + nr = cmm_get_timed_pages(); + len = sprintf(buf, "%ld\n", nr); if (len > *lenp) len = *lenp; if (copy_to_user(buffer, buf, len)) @@ -302,7 +309,7 @@ cmm_timeout_handler(ctl_table *ctl, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { char buf[64], *p; - long pages, seconds; + long nr, seconds; int len; if (!*lenp || (*ppos && !write)) { @@ -317,10 +324,10 @@ cmm_timeout_handler(ctl_table *ctl, int write, struct file *filp, return -EFAULT; buf[sizeof(buf) - 1] = '\0'; cmm_skip_blanks(buf, &p); - pages = cmm_strtoul(p, &p); + nr = simple_strtoul(p, &p, 0); cmm_skip_blanks(p, &p); - seconds = cmm_strtoul(p, &p); - cmm_set_timeout(pages, seconds); + seconds = simple_strtoul(p, &p, 0); + cmm_set_timeout(nr, seconds); } else { len = sprintf(buf, "%ld %ld\n", cmm_timeout_pages, cmm_timeout_seconds); @@ -373,7 +380,7 @@ static struct ctl_table cmm_dir_table[] = { static void cmm_smsg_target(char *from, char *msg) { - long pages, seconds; + long nr, seconds; if (strlen(sender) > 0 && strcmp(from, sender) != 0) return; @@ -382,27 +389,27 @@ cmm_smsg_target(char *from, char *msg) if (strncmp(msg, "SHRINK", 6) == 0) { if (!cmm_skip_blanks(msg + 6, &msg)) return; - pages = cmm_strtoul(msg, &msg); + nr = simple_strtoul(msg, &msg, 0); cmm_skip_blanks(msg, &msg); if (*msg == '\0') - cmm_set_pages(pages); + cmm_set_pages(nr); } else if (strncmp(msg, "RELEASE", 7) == 0) { if (!cmm_skip_blanks(msg + 7, &msg)) return; - pages = cmm_strtoul(msg, &msg); + nr = simple_strtoul(msg, &msg, 0); cmm_skip_blanks(msg, &msg); if (*msg == '\0') - cmm_add_timed_pages(pages); + cmm_add_timed_pages(nr); } else if (strncmp(msg, "REUSE", 5) == 0) { if (!cmm_skip_blanks(msg + 5, &msg)) return; - pages = cmm_strtoul(msg, &msg); + nr = simple_strtoul(msg, &msg, 0); if (!cmm_skip_blanks(msg, &msg)) return; - seconds = cmm_strtoul(msg, &msg); + seconds = simple_strtoul(msg, &msg, 0); cmm_skip_blanks(msg, &msg); if (*msg == '\0') - cmm_set_timeout(pages, seconds); + cmm_set_timeout(nr, seconds); } } #endif @@ -412,21 +419,49 @@ struct ctl_table_header *cmm_sysctl_header; static int cmm_init (void) { + int rc = -ENOMEM; + #ifdef CONFIG_CMM_PROC cmm_sysctl_header = register_sysctl_table(cmm_dir_table, 1); + if (!cmm_sysctl_header) + goto out; #endif #ifdef CONFIG_CMM_IUCV - smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); + rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); + if (rc < 0) + goto out_smsg; #endif - INIT_WORK(&cmm_thread_starter, (void *) cmm_start_thread, NULL); + rc = register_oom_notifier(&cmm_oom_nb); + if (rc < 0) + goto out_oom_notify; init_waitqueue_head(&cmm_thread_wait); init_timer(&cmm_timer); - return 0; + cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); + rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0; + if (!rc) + goto out; + /* + * kthread_create failed. undo all the stuff from above again. + */ + unregister_oom_notifier(&cmm_oom_nb); + +out_oom_notify: +#ifdef CONFIG_CMM_IUCV + smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); +out_smsg: +#endif +#ifdef CONFIG_CMM_PROC + unregister_sysctl_table(cmm_sysctl_header); +#endif +out: + return rc; } static void cmm_exit(void) { + kthread_stop(cmm_thread_ptr); + unregister_oom_notifier(&cmm_oom_nb); cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); #ifdef CONFIG_CMM_PROC diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 9b11e3e20903..226275d5c4f6 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -142,17 +142,17 @@ dcss_diag (__u8 func, void *parameter, rx = (unsigned long) parameter; ry = (unsigned long) func; - __asm__ __volatile__( + asm volatile( #ifdef CONFIG_64BIT - " sam31\n" // switch to 31 bit - " diag %0,%1,0x64\n" - " sam64\n" // switch back to 64 bit + " sam31\n" + " diag %0,%1,0x64\n" + " sam64\n" #else - " diag %0,%1,0x64\n" + " diag %0,%1,0x64\n" #endif - " ipm %2\n" - " srl %2,28\n" - : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc" ); + " ipm %2\n" + " srl %2,28\n" + : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc"); *ret1 = rx; *ret2 = ry; return rc; diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 7cd82575813d..9c3c19fe62fc 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -25,10 +25,12 @@ #include <linux/console.h> #include <linux/module.h> #include <linux/hardirq.h> +#include <linux/kprobes.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/pgtable.h> +#include <asm/kdebug.h> #ifndef CONFIG_64BIT #define __FAIL_ADDR_MASK 0x7ffff000 @@ -48,6 +50,38 @@ extern int sysctl_userprocess_debug; extern void die(const char *,struct pt_regs *,long); +#ifdef CONFIG_KPROBES +ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); +int register_page_fault_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); +} + +int unregister_page_fault_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); +} + +static inline int notify_page_fault(enum die_val val, const char *str, + struct pt_regs *regs, long err, int trap, int sig) +{ + struct die_args args = { + .regs = regs, + .str = str, + .err = err, + .trapnr = trap, + .signr = sig + }; + return atomic_notifier_call_chain(¬ify_page_fault_chain, val, &args); +} +#else +static inline int notify_page_fault(enum die_val val, const char *str, + struct pt_regs *regs, long err, int trap, int sig) +{ + return NOTIFY_DONE; +} +#endif + extern spinlock_t timerlist_lock; /* @@ -159,7 +193,7 @@ static void do_sigsegv(struct pt_regs *regs, unsigned long error_code, * 11 Page translation -> Not present (nullification) * 3b Region third trans. -> Not present (nullification) */ -static inline void +static inline void __kprobes do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection) { struct task_struct *tsk; @@ -173,6 +207,10 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection) tsk = current; mm = tsk->mm; + if (notify_page_fault(DIE_PAGE_FAULT, "page fault", regs, error_code, 14, + SIGSEGV) == NOTIFY_STOP) + return; + /* * Check for low-address protection. This needs to be treated * as a special case because the translation exception code @@ -315,8 +353,9 @@ no_context: */ out_of_memory: up_read(&mm->mmap_sem); - if (tsk->pid == 1) { + if (is_init(tsk)) { yield(); + down_read(&mm->mmap_sem); goto survive; } printk("VM: killing process %s\n", tsk->comm); @@ -385,20 +424,13 @@ int pfault_init(void) if (pfault_disable) return -1; - __asm__ __volatile__( - " diag %1,%0,0x258\n" - "0: j 2f\n" - "1: la %0,8\n" + asm volatile( + " diag %1,%0,0x258\n" + "0: j 2f\n" + "1: la %0,8\n" "2:\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" -#ifndef CONFIG_64BIT - " .long 0b,1b\n" -#else /* CONFIG_64BIT */ - " .quad 0b,1b\n" -#endif /* CONFIG_64BIT */ - ".previous" - : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc" ); + EX_TABLE(0b,1b) + : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc"); __ctl_set_bit(0, 9); return rc; } @@ -411,18 +443,11 @@ void pfault_fini(void) if (pfault_disable) return; __ctl_clear_bit(0,9); - __asm__ __volatile__( - " diag %0,0,0x258\n" + asm volatile( + " diag %0,0,0x258\n" "0:\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" -#ifndef CONFIG_64BIT - " .long 0b,0b\n" -#else /* CONFIG_64BIT */ - " .quad 0b,0b\n" -#endif /* CONFIG_64BIT */ - ".previous" - : : "a" (&refbk), "m" (refbk) : "cc" ); + EX_TABLE(0b,0b) + : : "a" (&refbk), "m" (refbk) : "cc"); } asmlinkage void diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 6e6b6de77770..127044e1707c 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -45,26 +45,17 @@ void diag10(unsigned long addr) { if (addr >= 0x7ff00000) return; + asm volatile( #ifdef CONFIG_64BIT - asm volatile ( - " sam31\n" - " diag %0,%0,0x10\n" - "0: sam64\n" - ".section __ex_table,\"a\"\n" - " .align 8\n" - " .quad 0b, 0b\n" - ".previous\n" - : : "a" (addr)); + " sam31\n" + " diag %0,%0,0x10\n" + "0: sam64\n" #else - asm volatile ( - " diag %0,%0,0x10\n" + " diag %0,%0,0x10\n" "0:\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 0b, 0b\n" - ".previous\n" - : : "a" (addr)); #endif + EX_TABLE(0b,0b) + : : "a" (addr)); } void show_mem(void) @@ -108,16 +99,23 @@ void __init paging_init(void) unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE; static const int ssm_mask = 0x04000000L; unsigned long ro_start_pfn, ro_end_pfn; + unsigned long zones_size[MAX_NR_ZONES]; ro_start_pfn = PFN_DOWN((unsigned long)&__start_rodata); ro_end_pfn = PFN_UP((unsigned long)&__end_rodata); + memset(zones_size, 0, sizeof(zones_size)); + zones_size[ZONE_DMA] = max_low_pfn; + free_area_init_node(0, &contig_page_data, zones_size, + __pa(PAGE_OFFSET) >> PAGE_SHIFT, + zholes_size); + /* unmap whole virtual address space */ pg_dir = swapper_pg_dir; - for (i=0;i<KERNEL_PGD_PTRS;i++) - pmd_clear((pmd_t*)pg_dir++); + for (i = 0; i < PTRS_PER_PGD; i++) + pmd_clear((pmd_t *) pg_dir++); /* * map whole physical memory to virtual memory (identity mapping) @@ -131,10 +129,7 @@ void __init paging_init(void) */ pg_table = (pte_t *) alloc_bootmem_pages(PAGE_SIZE); - pg_dir->pgd0 = (_PAGE_TABLE | __pa(pg_table)); - pg_dir->pgd1 = (_PAGE_TABLE | (__pa(pg_table)+1024)); - pg_dir->pgd2 = (_PAGE_TABLE | (__pa(pg_table)+2048)); - pg_dir->pgd3 = (_PAGE_TABLE | (__pa(pg_table)+3072)); + pmd_populate_kernel(&init_mm, (pmd_t *) pg_dir, pg_table); pg_dir++; for (tmp = 0 ; tmp < PTRS_PER_PTE ; tmp++,pg_table++) { @@ -143,8 +138,8 @@ void __init paging_init(void) else pte = pfn_pte(pfn, PAGE_KERNEL); if (pfn >= max_low_pfn) - pte_clear(&init_mm, 0, &pte); - set_pte(pg_table, pte); + pte_val(pte) = _PAGE_TYPE_EMPTY; + set_pte(pg_table, pte); pfn++; } } @@ -152,23 +147,12 @@ void __init paging_init(void) S390_lowcore.kernel_asce = pgdir_k; /* enable virtual mapping in kernel mode */ - __asm__ __volatile__(" LCTL 1,1,%0\n" - " LCTL 7,7,%0\n" - " LCTL 13,13,%0\n" - " SSM %1" - : : "m" (pgdir_k), "m" (ssm_mask)); + __ctl_load(pgdir_k, 1, 1); + __ctl_load(pgdir_k, 7, 7); + __ctl_load(pgdir_k, 13, 13); + __raw_local_irq_ssm(ssm_mask); local_flush_tlb(); - - { - unsigned long zones_size[MAX_NR_ZONES]; - - memset(zones_size, 0, sizeof(zones_size)); - zones_size[ZONE_DMA] = max_low_pfn; - free_area_init_node(0, &contig_page_data, zones_size, - __pa(PAGE_OFFSET) >> PAGE_SHIFT, - zholes_size); - } return; } @@ -236,10 +220,8 @@ void __init paging_init(void) pte = pfn_pte(pfn, __pgprot(_PAGE_RO)); else pte = pfn_pte(pfn, PAGE_KERNEL); - if (pfn >= max_low_pfn) { - pte_clear(&init_mm, 0, &pte); - continue; - } + if (pfn >= max_low_pfn) + pte_val(pte) = _PAGE_TYPE_EMPTY; set_pte(pt_dir, pte); pfn++; } @@ -249,11 +231,10 @@ void __init paging_init(void) S390_lowcore.kernel_asce = pgdir_k; /* enable virtual mapping in kernel mode */ - __asm__ __volatile__("lctlg 1,1,%0\n\t" - "lctlg 7,7,%0\n\t" - "lctlg 13,13,%0\n\t" - "ssm %1" - : :"m" (pgdir_k), "m" (ssm_mask)); + __ctl_load(pgdir_k, 1, 1); + __ctl_load(pgdir_k, 7, 7); + __ctl_load(pgdir_k, 13, 13); + __raw_local_irq_ssm(ssm_mask); local_flush_tlb(); |