mirror of
https://github.com/adulau/aha.git
synced 2025-01-03 14:43:17 +00:00
Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6: (37 commits) [S390] Avoid excessive inlining. [S390] Mark kernel text section read-only. [S390] Convert memory detection into C code. [S390] Calibrate delay and bogomips. [S390] Hypervisor filesystem (s390_hypfs) for z/VM [S390] Add crypto support for 3592 tape devices [S390] boot from NSS support [S390] Support for s390 Pseudo Random Number Generator [S390] ETR support. [S390] noexec protection [S390] move crypto options and some cleanup. [S390] cio: Don't spam debug feature. [S390] Cleanup of CHSC event handling. [S390] cio: declare hardware structures packed. [S390] Add set_fs(USER_DS) to start_thread(). [S390] cio: Catch operand exceptions on stsch. [S390] Fix register usage description. [S390] kretprobe_trampoline_holder() in wrong section. [S390] Fix kprobes breakpoint handling. [S390] Update maintainers file. ...
This commit is contained in:
commit
02aedd69e2
168 changed files with 5591 additions and 2242 deletions
|
@ -480,7 +480,7 @@ r2 argument 0 / return value 0 call-clobbered
|
||||||
r3 argument 1 / return value 1 (if long long) call-clobbered
|
r3 argument 1 / return value 1 (if long long) call-clobbered
|
||||||
r4 argument 2 call-clobbered
|
r4 argument 2 call-clobbered
|
||||||
r5 argument 3 call-clobbered
|
r5 argument 3 call-clobbered
|
||||||
r6 argument 5 saved
|
r6 argument 4 saved
|
||||||
r7 pointer-to arguments 5 to ... saved
|
r7 pointer-to arguments 5 to ... saved
|
||||||
r8 this & that saved
|
r8 this & that saved
|
||||||
r9 this & that saved
|
r9 this & that saved
|
||||||
|
|
|
@ -2791,7 +2791,7 @@ M: schwidefsky@de.ibm.com
|
||||||
P: Heiko Carstens
|
P: Heiko Carstens
|
||||||
M: heiko.carstens@de.ibm.com
|
M: heiko.carstens@de.ibm.com
|
||||||
M: linux390@de.ibm.com
|
M: linux390@de.ibm.com
|
||||||
L: linux-390@vm.marist.edu
|
L: linux-s390@vger.kernel.org
|
||||||
W: http://www.ibm.com/developerworks/linux/linux390/
|
W: http://www.ibm.com/developerworks/linux/linux390/
|
||||||
S: Supported
|
S: Supported
|
||||||
|
|
||||||
|
@ -2799,7 +2799,7 @@ S390 NETWORK DRIVERS
|
||||||
P: Frank Pavlic
|
P: Frank Pavlic
|
||||||
M: fpavlic@de.ibm.com
|
M: fpavlic@de.ibm.com
|
||||||
M: linux390@de.ibm.com
|
M: linux390@de.ibm.com
|
||||||
L: linux-390@vm.marist.edu
|
L: linux-s390@vger.kernel.org
|
||||||
W: http://www.ibm.com/developerworks/linux/linux390/
|
W: http://www.ibm.com/developerworks/linux/linux390/
|
||||||
S: Supported
|
S: Supported
|
||||||
|
|
||||||
|
@ -2807,7 +2807,7 @@ S390 ZFCP DRIVER
|
||||||
P: Swen Schillig
|
P: Swen Schillig
|
||||||
M: swen@vnet.ibm.com
|
M: swen@vnet.ibm.com
|
||||||
M: linux390@de.ibm.com
|
M: linux390@de.ibm.com
|
||||||
L: linux-390@vm.marist.edu
|
L: linux-s390@vger.kernel.org
|
||||||
W: http://www.ibm.com/developerworks/linux/linux390/
|
W: http://www.ibm.com/developerworks/linux/linux390/
|
||||||
S: Supported
|
S: Supported
|
||||||
|
|
||||||
|
|
|
@ -34,10 +34,6 @@ config GENERIC_HWEIGHT
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
config GENERIC_CALIBRATE_DELAY
|
|
||||||
bool
|
|
||||||
default y
|
|
||||||
|
|
||||||
config GENERIC_TIME
|
config GENERIC_TIME
|
||||||
def_bool y
|
def_bool y
|
||||||
|
|
||||||
|
@ -134,6 +130,31 @@ config AUDIT_ARCH
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config S390_SWITCH_AMODE
|
||||||
|
bool "Switch kernel/user addressing modes"
|
||||||
|
help
|
||||||
|
This option allows to switch the addressing modes of kernel and user
|
||||||
|
space. The kernel parameter switch_amode=on will enable this feature,
|
||||||
|
default is disabled. Enabling this (via kernel parameter) on machines
|
||||||
|
earlier than IBM System z9-109 EC/BC will reduce system performance.
|
||||||
|
|
||||||
|
Note that this option will also be selected by selecting the execute
|
||||||
|
protection option below. Enabling the execute protection via the
|
||||||
|
noexec kernel parameter will also switch the addressing modes,
|
||||||
|
independent of the switch_amode kernel parameter.
|
||||||
|
|
||||||
|
|
||||||
|
config S390_EXEC_PROTECT
|
||||||
|
bool "Data execute protection"
|
||||||
|
select S390_SWITCH_AMODE
|
||||||
|
help
|
||||||
|
This option allows to enable a buffer overflow protection for user
|
||||||
|
space programs and it also selects the addressing mode option above.
|
||||||
|
The kernel parameter noexec=on will enable this feature and also
|
||||||
|
switch the addressing modes, default is disabled. Enabling this (via
|
||||||
|
kernel parameter) on machines earlier than IBM System z9-109 EC/BC
|
||||||
|
will reduce system performance.
|
||||||
|
|
||||||
comment "Code generation options"
|
comment "Code generation options"
|
||||||
|
|
||||||
choice
|
choice
|
||||||
|
|
|
@ -81,7 +81,7 @@ static struct ctl_table appldata_dir_table[] = {
|
||||||
/*
|
/*
|
||||||
* Timer
|
* Timer
|
||||||
*/
|
*/
|
||||||
DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
|
static DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
|
||||||
static atomic_t appldata_expire_count = ATOMIC_INIT(0);
|
static atomic_t appldata_expire_count = ATOMIC_INIT(0);
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(appldata_timer_lock);
|
static DEFINE_SPINLOCK(appldata_timer_lock);
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
* book:
|
* book:
|
||||||
* http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
|
* http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
|
||||||
*/
|
*/
|
||||||
struct appldata_mem_data {
|
static struct appldata_mem_data {
|
||||||
u64 timestamp;
|
u64 timestamp;
|
||||||
u32 sync_count_1; /* after VM collected the record data, */
|
u32 sync_count_1; /* after VM collected the record data, */
|
||||||
u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
|
u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
* book:
|
* book:
|
||||||
* http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
|
* http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
|
||||||
*/
|
*/
|
||||||
struct appldata_net_sum_data {
|
static struct appldata_net_sum_data {
|
||||||
u64 timestamp;
|
u64 timestamp;
|
||||||
u32 sync_count_1; /* after VM collected the record data, */
|
u32 sync_count_1; /* after VM collected the record data, */
|
||||||
u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
|
u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the
|
||||||
|
|
60
arch/s390/crypto/Kconfig
Normal file
60
arch/s390/crypto/Kconfig
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
config CRYPTO_SHA1_S390
|
||||||
|
tristate "SHA1 digest algorithm"
|
||||||
|
depends on S390
|
||||||
|
select CRYPTO_ALGAPI
|
||||||
|
help
|
||||||
|
This is the s390 hardware accelerated implementation of the
|
||||||
|
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
|
||||||
|
|
||||||
|
config CRYPTO_SHA256_S390
|
||||||
|
tristate "SHA256 digest algorithm"
|
||||||
|
depends on S390
|
||||||
|
select CRYPTO_ALGAPI
|
||||||
|
help
|
||||||
|
This is the s390 hardware accelerated implementation of the
|
||||||
|
SHA256 secure hash standard (DFIPS 180-2).
|
||||||
|
|
||||||
|
This version of SHA implements a 256 bit hash with 128 bits of
|
||||||
|
security against collision attacks.
|
||||||
|
|
||||||
|
config CRYPTO_DES_S390
|
||||||
|
tristate "DES and Triple DES cipher algorithms"
|
||||||
|
depends on S390
|
||||||
|
select CRYPTO_ALGAPI
|
||||||
|
select CRYPTO_BLKCIPHER
|
||||||
|
help
|
||||||
|
This us the s390 hardware accelerated implementation of the
|
||||||
|
DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
|
||||||
|
|
||||||
|
config CRYPTO_AES_S390
|
||||||
|
tristate "AES cipher algorithms"
|
||||||
|
depends on S390
|
||||||
|
select CRYPTO_ALGAPI
|
||||||
|
select CRYPTO_BLKCIPHER
|
||||||
|
help
|
||||||
|
This is the s390 hardware accelerated implementation of the
|
||||||
|
AES cipher algorithms (FIPS-197). AES uses the Rijndael
|
||||||
|
algorithm.
|
||||||
|
|
||||||
|
Rijndael appears to be consistently a very good performer in
|
||||||
|
both hardware and software across a wide range of computing
|
||||||
|
environments regardless of its use in feedback or non-feedback
|
||||||
|
modes. Its key setup time is excellent, and its key agility is
|
||||||
|
good. Rijndael's very low memory requirements make it very well
|
||||||
|
suited for restricted-space environments, in which it also
|
||||||
|
demonstrates excellent performance. Rijndael's operations are
|
||||||
|
among the easiest to defend against power and timing attacks.
|
||||||
|
|
||||||
|
On s390 the System z9-109 currently only supports the key size
|
||||||
|
of 128 bit.
|
||||||
|
|
||||||
|
config S390_PRNG
|
||||||
|
tristate "Pseudo random number generator device driver"
|
||||||
|
depends on S390
|
||||||
|
default "m"
|
||||||
|
help
|
||||||
|
Select this option if you want to use the s390 pseudo random number
|
||||||
|
generator. The PRNG is part of the cryptograhic processor functions
|
||||||
|
and uses triple-DES to generate secure random numbers like the
|
||||||
|
ANSI X9.17 standard. The PRNG is usable via the char device
|
||||||
|
/dev/prandom.
|
|
@ -6,5 +6,4 @@ obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o
|
||||||
obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o
|
obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o
|
||||||
obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o
|
obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o
|
||||||
obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
|
obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
|
||||||
|
obj-$(CONFIG_S390_PRNG) += prng.o
|
||||||
obj-$(CONFIG_CRYPTO_TEST) += crypt_s390_query.o
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* s390 implementation of the AES Cipher Algorithm.
|
* s390 implementation of the AES Cipher Algorithm.
|
||||||
*
|
*
|
||||||
* s390 Version:
|
* s390 Version:
|
||||||
* Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation
|
* Copyright IBM Corp. 2005,2007
|
||||||
* Author(s): Jan Glauber (jang@de.ibm.com)
|
* Author(s): Jan Glauber (jang@de.ibm.com)
|
||||||
*
|
*
|
||||||
* Derived from "crypto/aes.c"
|
* Derived from "crypto/aes.c"
|
||||||
|
@ -27,9 +27,11 @@
|
||||||
/* data block size for all key lengths */
|
/* data block size for all key lengths */
|
||||||
#define AES_BLOCK_SIZE 16
|
#define AES_BLOCK_SIZE 16
|
||||||
|
|
||||||
int has_aes_128 = 0;
|
#define AES_KEYLEN_128 1
|
||||||
int has_aes_192 = 0;
|
#define AES_KEYLEN_192 2
|
||||||
int has_aes_256 = 0;
|
#define AES_KEYLEN_256 4
|
||||||
|
|
||||||
|
static char keylen_flag = 0;
|
||||||
|
|
||||||
struct s390_aes_ctx {
|
struct s390_aes_ctx {
|
||||||
u8 iv[AES_BLOCK_SIZE];
|
u8 iv[AES_BLOCK_SIZE];
|
||||||
|
@ -47,20 +49,19 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
|
||||||
|
|
||||||
switch (key_len) {
|
switch (key_len) {
|
||||||
case 16:
|
case 16:
|
||||||
if (!has_aes_128)
|
if (!(keylen_flag & AES_KEYLEN_128))
|
||||||
goto fail;
|
goto fail;
|
||||||
break;
|
break;
|
||||||
case 24:
|
case 24:
|
||||||
if (!has_aes_192)
|
if (!(keylen_flag & AES_KEYLEN_192))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 32:
|
case 32:
|
||||||
if (!has_aes_256)
|
if (!(keylen_flag & AES_KEYLEN_256))
|
||||||
goto fail;
|
goto fail;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* invalid key length */
|
|
||||||
goto fail;
|
goto fail;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -322,34 +323,32 @@ static int __init aes_init(void)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (crypt_s390_func_available(KM_AES_128_ENCRYPT))
|
if (crypt_s390_func_available(KM_AES_128_ENCRYPT))
|
||||||
has_aes_128 = 1;
|
keylen_flag |= AES_KEYLEN_128;
|
||||||
if (crypt_s390_func_available(KM_AES_192_ENCRYPT))
|
if (crypt_s390_func_available(KM_AES_192_ENCRYPT))
|
||||||
has_aes_192 = 1;
|
keylen_flag |= AES_KEYLEN_192;
|
||||||
if (crypt_s390_func_available(KM_AES_256_ENCRYPT))
|
if (crypt_s390_func_available(KM_AES_256_ENCRYPT))
|
||||||
has_aes_256 = 1;
|
keylen_flag |= AES_KEYLEN_256;
|
||||||
|
|
||||||
if (!has_aes_128 && !has_aes_192 && !has_aes_256)
|
if (!keylen_flag)
|
||||||
return -ENOSYS;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
/* z9 109 and z9 BC/EC only support 128 bit key length */
|
||||||
|
if (keylen_flag == AES_KEYLEN_128)
|
||||||
|
printk(KERN_INFO
|
||||||
|
"aes_s390: hardware acceleration only available for"
|
||||||
|
"128 bit keys\n");
|
||||||
|
|
||||||
ret = crypto_register_alg(&aes_alg);
|
ret = crypto_register_alg(&aes_alg);
|
||||||
if (ret != 0) {
|
if (ret)
|
||||||
printk(KERN_INFO "crypt_s390: aes-s390 couldn't be loaded.\n");
|
|
||||||
goto aes_err;
|
goto aes_err;
|
||||||
}
|
|
||||||
|
|
||||||
ret = crypto_register_alg(&ecb_aes_alg);
|
ret = crypto_register_alg(&ecb_aes_alg);
|
||||||
if (ret != 0) {
|
if (ret)
|
||||||
printk(KERN_INFO
|
|
||||||
"crypt_s390: ecb-aes-s390 couldn't be loaded.\n");
|
|
||||||
goto ecb_aes_err;
|
goto ecb_aes_err;
|
||||||
}
|
|
||||||
|
|
||||||
ret = crypto_register_alg(&cbc_aes_alg);
|
ret = crypto_register_alg(&cbc_aes_alg);
|
||||||
if (ret != 0) {
|
if (ret)
|
||||||
printk(KERN_INFO
|
|
||||||
"crypt_s390: cbc-aes-s390 couldn't be loaded.\n");
|
|
||||||
goto cbc_aes_err;
|
goto cbc_aes_err;
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
*
|
*
|
||||||
* Support for s390 cryptographic instructions.
|
* Support for s390 cryptographic instructions.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
|
* Copyright IBM Corp. 2003,2007
|
||||||
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
|
* Author(s): Thomas Spatzier
|
||||||
|
* Jan Glauber (jan.glauber@de.ibm.com)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
@ -32,7 +33,8 @@ enum crypt_s390_operations {
|
||||||
CRYPT_S390_KMAC = 0x0500
|
CRYPT_S390_KMAC = 0x0500
|
||||||
};
|
};
|
||||||
|
|
||||||
/* function codes for KM (CIPHER MESSAGE) instruction
|
/*
|
||||||
|
* function codes for KM (CIPHER MESSAGE) instruction
|
||||||
* 0x80 is the decipher modifier bit
|
* 0x80 is the decipher modifier bit
|
||||||
*/
|
*/
|
||||||
enum crypt_s390_km_func {
|
enum crypt_s390_km_func {
|
||||||
|
@ -51,7 +53,8 @@ enum crypt_s390_km_func {
|
||||||
KM_AES_256_DECRYPT = CRYPT_S390_KM | 0x14 | 0x80,
|
KM_AES_256_DECRYPT = CRYPT_S390_KM | 0x14 | 0x80,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* function codes for KMC (CIPHER MESSAGE WITH CHAINING)
|
/*
|
||||||
|
* function codes for KMC (CIPHER MESSAGE WITH CHAINING)
|
||||||
* instruction
|
* instruction
|
||||||
*/
|
*/
|
||||||
enum crypt_s390_kmc_func {
|
enum crypt_s390_kmc_func {
|
||||||
|
@ -68,9 +71,11 @@ enum crypt_s390_kmc_func {
|
||||||
KMC_AES_192_DECRYPT = CRYPT_S390_KMC | 0x13 | 0x80,
|
KMC_AES_192_DECRYPT = CRYPT_S390_KMC | 0x13 | 0x80,
|
||||||
KMC_AES_256_ENCRYPT = CRYPT_S390_KMC | 0x14,
|
KMC_AES_256_ENCRYPT = CRYPT_S390_KMC | 0x14,
|
||||||
KMC_AES_256_DECRYPT = CRYPT_S390_KMC | 0x14 | 0x80,
|
KMC_AES_256_DECRYPT = CRYPT_S390_KMC | 0x14 | 0x80,
|
||||||
|
KMC_PRNG = CRYPT_S390_KMC | 0x43,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
|
/*
|
||||||
|
* function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
|
||||||
* instruction
|
* instruction
|
||||||
*/
|
*/
|
||||||
enum crypt_s390_kimd_func {
|
enum crypt_s390_kimd_func {
|
||||||
|
@ -79,7 +84,8 @@ enum crypt_s390_kimd_func {
|
||||||
KIMD_SHA_256 = CRYPT_S390_KIMD | 2,
|
KIMD_SHA_256 = CRYPT_S390_KIMD | 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
|
/*
|
||||||
|
* function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
|
||||||
* instruction
|
* instruction
|
||||||
*/
|
*/
|
||||||
enum crypt_s390_klmd_func {
|
enum crypt_s390_klmd_func {
|
||||||
|
@ -88,7 +94,8 @@ enum crypt_s390_klmd_func {
|
||||||
KLMD_SHA_256 = CRYPT_S390_KLMD | 2,
|
KLMD_SHA_256 = CRYPT_S390_KLMD | 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
|
/*
|
||||||
|
* function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
|
||||||
* instruction
|
* instruction
|
||||||
*/
|
*/
|
||||||
enum crypt_s390_kmac_func {
|
enum crypt_s390_kmac_func {
|
||||||
|
@ -98,229 +105,219 @@ enum crypt_s390_kmac_func {
|
||||||
KMAC_TDEA_192 = CRYPT_S390_KMAC | 3
|
KMAC_TDEA_192 = CRYPT_S390_KMAC | 3
|
||||||
};
|
};
|
||||||
|
|
||||||
/* status word for s390 crypto instructions' QUERY functions */
|
/**
|
||||||
struct crypt_s390_query_status {
|
* crypt_s390_km:
|
||||||
u64 high;
|
* @func: the function code passed to KM; see crypt_s390_km_func
|
||||||
u64 low;
|
* @param: address of parameter block; see POP for details on each func
|
||||||
};
|
* @dest: address of destination memory area
|
||||||
|
* @src: address of source memory area
|
||||||
/*
|
* @src_len: length of src operand in bytes
|
||||||
|
*
|
||||||
* Executes the KM (CIPHER MESSAGE) operation of the CPU.
|
* 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
|
* Returns -1 for failure, 0 for the query func, number of processed
|
||||||
* @param dest: address of destination memory area
|
* bytes for encryption/decryption funcs
|
||||||
* @param src: address of source memory area
|
|
||||||
* @param src_len: length of src operand in bytes
|
|
||||||
* @returns < zero for failure, 0 for the query func, number of processed bytes
|
|
||||||
* for encryption/decryption funcs
|
|
||||||
*/
|
*/
|
||||||
static inline int
|
static inline int crypt_s390_km(long func, void *param,
|
||||||
crypt_s390_km(long func, void* param, u8* dest, const u8* src, long src_len)
|
u8 *dest, const u8 *src, long src_len)
|
||||||
{
|
{
|
||||||
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
|
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
|
||||||
register void* __param asm("1") = param;
|
register void *__param asm("1") = param;
|
||||||
register const u8* __src asm("2") = src;
|
register const u8 *__src asm("2") = src;
|
||||||
register long __src_len asm("3") = src_len;
|
register long __src_len asm("3") = src_len;
|
||||||
register u8* __dest asm("4") = dest;
|
register u8 *__dest asm("4") = dest;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"0: .insn rre,0xb92e0000,%3,%1 \n" /* KM opcode */
|
"0: .insn rre,0xb92e0000,%3,%1 \n" /* KM opcode */
|
||||||
"1: brc 1,0b \n" /* handle partial completion */
|
"1: brc 1,0b \n" /* handle partial completion */
|
||||||
" ahi %0,%h7\n"
|
" la %0,0\n"
|
||||||
"2: ahi %0,%h8\n"
|
"2:\n"
|
||||||
"3:\n"
|
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
|
||||||
EX_TABLE(0b,3b) EX_TABLE(1b,2b)
|
|
||||||
: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
|
: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
|
||||||
: "d" (__func), "a" (__param), "0" (-EFAULT),
|
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
|
||||||
"K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU.
|
|
||||||
* @param func: the function code passed to KM; see crypt_s390_kmc_func
|
|
||||||
* @param param: address of parameter block; see POP for details on each func
|
|
||||||
* @param dest: address of destination memory area
|
|
||||||
* @param src: address of source memory area
|
|
||||||
* @param src_len: length of src operand in bytes
|
|
||||||
* @returns < zero for failure, 0 for the query func, number of processed bytes
|
|
||||||
* for encryption/decryption funcs
|
|
||||||
*/
|
|
||||||
static inline int
|
|
||||||
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 const u8* __src asm("2") = src;
|
|
||||||
register long __src_len asm("3") = src_len;
|
|
||||||
register u8* __dest asm("4") = dest;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
asm volatile(
|
|
||||||
"0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
|
|
||||||
"1: brc 1,0b \n" /* handle partial completion */
|
|
||||||
" 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation
|
|
||||||
* of the CPU.
|
|
||||||
* @param func: the function code passed to KM; see crypt_s390_kimd_func
|
|
||||||
* @param param: address of parameter block; see POP for details on each func
|
|
||||||
* @param src: address of source memory area
|
|
||||||
* @param src_len: length of src operand in bytes
|
|
||||||
* @returns < zero for failure, 0 for the query func, number of processed bytes
|
|
||||||
* for digest funcs
|
|
||||||
*/
|
|
||||||
static inline int
|
|
||||||
crypt_s390_kimd(long func, void* param, const u8* src, long src_len)
|
|
||||||
{
|
|
||||||
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
|
|
||||||
register void* __param asm("1") = param;
|
|
||||||
register const u8* __src asm("2") = src;
|
|
||||||
register long __src_len asm("3") = src_len;
|
|
||||||
int 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the CPU.
|
|
||||||
* @param func: the function code passed to KM; see crypt_s390_klmd_func
|
|
||||||
* @param param: address of parameter block; see POP for details on each func
|
|
||||||
* @param src: address of source memory area
|
|
||||||
* @param src_len: length of src operand in bytes
|
|
||||||
* @returns < zero for failure, 0 for the query func, number of processed bytes
|
|
||||||
* for digest funcs
|
|
||||||
*/
|
|
||||||
static inline int
|
|
||||||
crypt_s390_klmd(long func, void* param, const u8* src, long src_len)
|
|
||||||
{
|
|
||||||
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
|
|
||||||
register void* __param asm("1") = param;
|
|
||||||
register const u8* __src asm("2") = src;
|
|
||||||
register long __src_len asm("3") = src_len;
|
|
||||||
int 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation
|
|
||||||
* of the CPU.
|
|
||||||
* @param func: the function code passed to KM; see crypt_s390_klmd_func
|
|
||||||
* @param param: address of parameter block; see POP for details on each func
|
|
||||||
* @param src: address of source memory area
|
|
||||||
* @param src_len: length of src operand in bytes
|
|
||||||
* @returns < zero for failure, 0 for the query func, number of processed bytes
|
|
||||||
* for digest funcs
|
|
||||||
*/
|
|
||||||
static inline int
|
|
||||||
crypt_s390_kmac(long func, void* param, const u8* src, long src_len)
|
|
||||||
{
|
|
||||||
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
|
|
||||||
register void* __param asm("1") = param;
|
|
||||||
register const u8* __src asm("2") = src;
|
|
||||||
register long __src_len asm("3") = src_len;
|
|
||||||
int 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)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
|
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests if a specific crypto function is implemented on the machine.
|
* crypt_s390_kmc:
|
||||||
* @param func: the function code of the specific function; 0 if op in general
|
* @func: the function code passed to KM; see crypt_s390_kmc_func
|
||||||
* @return 1 if func available; 0 if func or op in general not available
|
* @param: address of parameter block; see POP for details on each func
|
||||||
|
* @dest: address of destination memory area
|
||||||
|
* @src: address of source memory area
|
||||||
|
* @src_len: length of src operand in bytes
|
||||||
|
*
|
||||||
|
* Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU.
|
||||||
|
*
|
||||||
|
* Returns -1 for failure, 0 for the query func, number of processed
|
||||||
|
* bytes for encryption/decryption funcs
|
||||||
*/
|
*/
|
||||||
static inline int
|
static inline int crypt_s390_kmc(long func, void *param,
|
||||||
crypt_s390_func_available(int func)
|
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 const u8 *__src asm("2") = src;
|
||||||
|
register long __src_len asm("3") = src_len;
|
||||||
|
register u8 *__dest asm("4") = dest;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
struct crypt_s390_query_status status = {
|
asm volatile(
|
||||||
.high = 0,
|
"0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
|
||||||
.low = 0
|
"1: brc 1,0b \n" /* handle partial completion */
|
||||||
};
|
" la %0,0\n"
|
||||||
switch (func & CRYPT_S390_OP_MASK){
|
"2:\n"
|
||||||
case CRYPT_S390_KM:
|
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
|
||||||
ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
|
: "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
|
||||||
break;
|
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
|
||||||
case CRYPT_S390_KMC:
|
if (ret < 0)
|
||||||
ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
|
return ret;
|
||||||
break;
|
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
|
||||||
case CRYPT_S390_KIMD:
|
|
||||||
ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
|
|
||||||
break;
|
|
||||||
case CRYPT_S390_KLMD:
|
|
||||||
ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
|
|
||||||
break;
|
|
||||||
case CRYPT_S390_KMAC:
|
|
||||||
ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = 0;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (ret >= 0){
|
|
||||||
func &= CRYPT_S390_FUNC_MASK;
|
|
||||||
func &= 0x7f; //mask modifier bit
|
|
||||||
if (func < 64){
|
|
||||||
ret = (status.high >> (64 - func - 1)) & 0x1;
|
|
||||||
} else {
|
|
||||||
ret = (status.low >> (128 - func - 1)) & 0x1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret = 0;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // _CRYPTO_ARCH_S390_CRYPT_S390_H
|
/**
|
||||||
|
* crypt_s390_kimd:
|
||||||
|
* @func: the function code passed to KM; see crypt_s390_kimd_func
|
||||||
|
* @param: address of parameter block; see POP for details on each func
|
||||||
|
* @src: address of source memory area
|
||||||
|
* @src_len: length of src operand in bytes
|
||||||
|
*
|
||||||
|
* Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation
|
||||||
|
* of the CPU.
|
||||||
|
*
|
||||||
|
* Returns -1 for failure, 0 for the query func, number of processed
|
||||||
|
* bytes for digest funcs
|
||||||
|
*/
|
||||||
|
static inline int crypt_s390_kimd(long func, void *param,
|
||||||
|
const u8 *src, long src_len)
|
||||||
|
{
|
||||||
|
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
|
||||||
|
register void *__param asm("1") = param;
|
||||||
|
register const u8 *__src asm("2") = src;
|
||||||
|
register long __src_len asm("3") = src_len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
asm volatile(
|
||||||
|
"0: .insn rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */
|
||||||
|
"1: brc 1,0b \n" /* handle partial completion */
|
||||||
|
" la %0,0\n"
|
||||||
|
"2:\n"
|
||||||
|
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
|
||||||
|
: "=d" (ret), "+a" (__src), "+d" (__src_len)
|
||||||
|
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* crypt_s390_klmd:
|
||||||
|
* @func: the function code passed to KM; see crypt_s390_klmd_func
|
||||||
|
* @param: address of parameter block; see POP for details on each func
|
||||||
|
* @src: address of source memory area
|
||||||
|
* @src_len: length of src operand in bytes
|
||||||
|
*
|
||||||
|
* Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the CPU.
|
||||||
|
*
|
||||||
|
* Returns -1 for failure, 0 for the query func, number of processed
|
||||||
|
* bytes for digest funcs
|
||||||
|
*/
|
||||||
|
static inline int crypt_s390_klmd(long func, void *param,
|
||||||
|
const u8 *src, long src_len)
|
||||||
|
{
|
||||||
|
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
|
||||||
|
register void *__param asm("1") = param;
|
||||||
|
register const u8 *__src asm("2") = src;
|
||||||
|
register long __src_len asm("3") = src_len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
asm volatile(
|
||||||
|
"0: .insn rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */
|
||||||
|
"1: brc 1,0b \n" /* handle partial completion */
|
||||||
|
" la %0,0\n"
|
||||||
|
"2:\n"
|
||||||
|
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
|
||||||
|
: "=d" (ret), "+a" (__src), "+d" (__src_len)
|
||||||
|
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* crypt_s390_kmac:
|
||||||
|
* @func: the function code passed to KM; see crypt_s390_klmd_func
|
||||||
|
* @param: address of parameter block; see POP for details on each func
|
||||||
|
* @src: address of source memory area
|
||||||
|
* @src_len: length of src operand in bytes
|
||||||
|
*
|
||||||
|
* Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation
|
||||||
|
* of the CPU.
|
||||||
|
*
|
||||||
|
* Returns -1 for failure, 0 for the query func, number of processed
|
||||||
|
* bytes for digest funcs
|
||||||
|
*/
|
||||||
|
static inline int crypt_s390_kmac(long func, void *param,
|
||||||
|
const u8 *src, long src_len)
|
||||||
|
{
|
||||||
|
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
|
||||||
|
register void *__param asm("1") = param;
|
||||||
|
register const u8 *__src asm("2") = src;
|
||||||
|
register long __src_len asm("3") = src_len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
asm volatile(
|
||||||
|
"0: .insn rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */
|
||||||
|
"1: brc 1,0b \n" /* handle partial completion */
|
||||||
|
" la %0,0\n"
|
||||||
|
"2:\n"
|
||||||
|
EX_TABLE(0b,2b) EX_TABLE(1b,2b)
|
||||||
|
: "=d" (ret), "+a" (__src), "+d" (__src_len)
|
||||||
|
: "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* crypt_s390_func_available:
|
||||||
|
* @func: the function code of the specific function; 0 if op in general
|
||||||
|
*
|
||||||
|
* Tests if a specific crypto function is implemented on the machine.
|
||||||
|
*
|
||||||
|
* Returns 1 if func available; 0 if func or op in general not available
|
||||||
|
*/
|
||||||
|
static inline int crypt_s390_func_available(int func)
|
||||||
|
{
|
||||||
|
unsigned char status[16];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (func & CRYPT_S390_OP_MASK) {
|
||||||
|
case CRYPT_S390_KM:
|
||||||
|
ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
|
||||||
|
break;
|
||||||
|
case CRYPT_S390_KMC:
|
||||||
|
ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
|
||||||
|
break;
|
||||||
|
case CRYPT_S390_KIMD:
|
||||||
|
ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
|
||||||
|
break;
|
||||||
|
case CRYPT_S390_KLMD:
|
||||||
|
ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
|
||||||
|
break;
|
||||||
|
case CRYPT_S390_KMAC:
|
||||||
|
ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (ret < 0)
|
||||||
|
return 0;
|
||||||
|
func &= CRYPT_S390_FUNC_MASK;
|
||||||
|
func &= 0x7f; /* mask modifier bit */
|
||||||
|
return (status[func >> 3] & (0x80 >> (func & 7))) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */
|
||||||
|
|
|
@ -1,129 +0,0 @@
|
||||||
/*
|
|
||||||
* Cryptographic API.
|
|
||||||
*
|
|
||||||
* Support for s390 cryptographic instructions.
|
|
||||||
* Testing module for querying processor crypto capabilities.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
|
||||||
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <asm/errno.h>
|
|
||||||
#include "crypt_s390.h"
|
|
||||||
|
|
||||||
static void query_available_functions(void)
|
|
||||||
{
|
|
||||||
printk(KERN_INFO "#####################\n");
|
|
||||||
|
|
||||||
/* query available KM functions */
|
|
||||||
printk(KERN_INFO "KM_QUERY: %d\n",
|
|
||||||
crypt_s390_func_available(KM_QUERY));
|
|
||||||
printk(KERN_INFO "KM_DEA: %d\n",
|
|
||||||
crypt_s390_func_available(KM_DEA_ENCRYPT));
|
|
||||||
printk(KERN_INFO "KM_TDEA_128: %d\n",
|
|
||||||
crypt_s390_func_available(KM_TDEA_128_ENCRYPT));
|
|
||||||
printk(KERN_INFO "KM_TDEA_192: %d\n",
|
|
||||||
crypt_s390_func_available(KM_TDEA_192_ENCRYPT));
|
|
||||||
printk(KERN_INFO "KM_AES_128: %d\n",
|
|
||||||
crypt_s390_func_available(KM_AES_128_ENCRYPT));
|
|
||||||
printk(KERN_INFO "KM_AES_192: %d\n",
|
|
||||||
crypt_s390_func_available(KM_AES_192_ENCRYPT));
|
|
||||||
printk(KERN_INFO "KM_AES_256: %d\n",
|
|
||||||
crypt_s390_func_available(KM_AES_256_ENCRYPT));
|
|
||||||
|
|
||||||
/* query available KMC functions */
|
|
||||||
printk(KERN_INFO "KMC_QUERY: %d\n",
|
|
||||||
crypt_s390_func_available(KMC_QUERY));
|
|
||||||
printk(KERN_INFO "KMC_DEA: %d\n",
|
|
||||||
crypt_s390_func_available(KMC_DEA_ENCRYPT));
|
|
||||||
printk(KERN_INFO "KMC_TDEA_128: %d\n",
|
|
||||||
crypt_s390_func_available(KMC_TDEA_128_ENCRYPT));
|
|
||||||
printk(KERN_INFO "KMC_TDEA_192: %d\n",
|
|
||||||
crypt_s390_func_available(KMC_TDEA_192_ENCRYPT));
|
|
||||||
printk(KERN_INFO "KMC_AES_128: %d\n",
|
|
||||||
crypt_s390_func_available(KMC_AES_128_ENCRYPT));
|
|
||||||
printk(KERN_INFO "KMC_AES_192: %d\n",
|
|
||||||
crypt_s390_func_available(KMC_AES_192_ENCRYPT));
|
|
||||||
printk(KERN_INFO "KMC_AES_256: %d\n",
|
|
||||||
crypt_s390_func_available(KMC_AES_256_ENCRYPT));
|
|
||||||
|
|
||||||
/* query available KIMD functions */
|
|
||||||
printk(KERN_INFO "KIMD_QUERY: %d\n",
|
|
||||||
crypt_s390_func_available(KIMD_QUERY));
|
|
||||||
printk(KERN_INFO "KIMD_SHA_1: %d\n",
|
|
||||||
crypt_s390_func_available(KIMD_SHA_1));
|
|
||||||
printk(KERN_INFO "KIMD_SHA_256: %d\n",
|
|
||||||
crypt_s390_func_available(KIMD_SHA_256));
|
|
||||||
|
|
||||||
/* query available KLMD functions */
|
|
||||||
printk(KERN_INFO "KLMD_QUERY: %d\n",
|
|
||||||
crypt_s390_func_available(KLMD_QUERY));
|
|
||||||
printk(KERN_INFO "KLMD_SHA_1: %d\n",
|
|
||||||
crypt_s390_func_available(KLMD_SHA_1));
|
|
||||||
printk(KERN_INFO "KLMD_SHA_256: %d\n",
|
|
||||||
crypt_s390_func_available(KLMD_SHA_256));
|
|
||||||
|
|
||||||
/* query available KMAC functions */
|
|
||||||
printk(KERN_INFO "KMAC_QUERY: %d\n",
|
|
||||||
crypt_s390_func_available(KMAC_QUERY));
|
|
||||||
printk(KERN_INFO "KMAC_DEA: %d\n",
|
|
||||||
crypt_s390_func_available(KMAC_DEA));
|
|
||||||
printk(KERN_INFO "KMAC_TDEA_128: %d\n",
|
|
||||||
crypt_s390_func_available(KMAC_TDEA_128));
|
|
||||||
printk(KERN_INFO "KMAC_TDEA_192: %d\n",
|
|
||||||
crypt_s390_func_available(KMAC_TDEA_192));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int init(void)
|
|
||||||
{
|
|
||||||
struct crypt_s390_query_status status = {
|
|
||||||
.high = 0,
|
|
||||||
.low = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
printk(KERN_INFO "crypt_s390: querying available crypto functions\n");
|
|
||||||
crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
|
|
||||||
printk(KERN_INFO "KM:\t%016llx %016llx\n",
|
|
||||||
(unsigned long long) status.high,
|
|
||||||
(unsigned long long) status.low);
|
|
||||||
status.high = status.low = 0;
|
|
||||||
crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
|
|
||||||
printk(KERN_INFO "KMC:\t%016llx %016llx\n",
|
|
||||||
(unsigned long long) status.high,
|
|
||||||
(unsigned long long) status.low);
|
|
||||||
status.high = status.low = 0;
|
|
||||||
crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
|
|
||||||
printk(KERN_INFO "KIMD:\t%016llx %016llx\n",
|
|
||||||
(unsigned long long) status.high,
|
|
||||||
(unsigned long long) status.low);
|
|
||||||
status.high = status.low = 0;
|
|
||||||
crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
|
|
||||||
printk(KERN_INFO "KLMD:\t%016llx %016llx\n",
|
|
||||||
(unsigned long long) status.high,
|
|
||||||
(unsigned long long) status.low);
|
|
||||||
status.high = status.low = 0;
|
|
||||||
crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
|
|
||||||
printk(KERN_INFO "KMAC:\t%016llx %016llx\n",
|
|
||||||
(unsigned long long) status.high,
|
|
||||||
(unsigned long long) status.low);
|
|
||||||
|
|
||||||
query_available_functions();
|
|
||||||
return -ECANCELED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __exit cleanup(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
module_init(init);
|
|
||||||
module_exit(cleanup);
|
|
||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
|
|
@ -10,8 +10,9 @@
|
||||||
* scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL.
|
* scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL.
|
||||||
*
|
*
|
||||||
* s390 Version:
|
* s390 Version:
|
||||||
* Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
|
* Copyright IBM Corp. 2003
|
||||||
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
|
* Author(s): Thomas Spatzier
|
||||||
|
* Jan Glauber (jan.glauber@de.ibm.com)
|
||||||
*
|
*
|
||||||
* Derived from "crypto/des.c"
|
* Derived from "crypto/des.c"
|
||||||
* Copyright (c) 1992 Dana L. How.
|
* Copyright (c) 1992 Dana L. How.
|
||||||
|
@ -30,6 +31,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
|
#include "crypto_des.h"
|
||||||
|
|
||||||
#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o))
|
#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o))
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
*
|
*
|
||||||
* s390 implementation of the DES Cipher Algorithm.
|
* s390 implementation of the DES Cipher Algorithm.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
* Copyright IBM Corp. 2003,2007
|
||||||
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
|
* Author(s): Thomas Spatzier
|
||||||
*
|
* Jan Glauber (jan.glauber@de.ibm.com)
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -557,7 +557,7 @@ static int init(void)
|
||||||
if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
|
if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
|
||||||
!crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
|
!crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
|
||||||
!crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
|
!crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
|
||||||
return -ENOSYS;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
ret = crypto_register_alg(&des_alg);
|
ret = crypto_register_alg(&des_alg);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
213
arch/s390/crypto/prng.c
Normal file
213
arch/s390/crypto/prng.c
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2006,2007
|
||||||
|
* Author(s): Jan Glauber <jan.glauber@de.ibm.com>
|
||||||
|
* Driver for the s390 pseudo random number generator
|
||||||
|
*/
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/random.h>
|
||||||
|
#include <asm/debug.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
|
#include "crypt_s390.h"
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Jan Glauber <jan.glauber@de.ibm.com>");
|
||||||
|
MODULE_DESCRIPTION("s390 PRNG interface");
|
||||||
|
|
||||||
|
static int prng_chunk_size = 256;
|
||||||
|
module_param(prng_chunk_size, int, S_IRUSR | S_IRGRP | S_IROTH);
|
||||||
|
MODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes");
|
||||||
|
|
||||||
|
static int prng_entropy_limit = 4096;
|
||||||
|
module_param(prng_entropy_limit, int, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
|
||||||
|
MODULE_PARM_DESC(prng_entropy_limit,
|
||||||
|
"PRNG add entropy after that much bytes were produced");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Any one who considers arithmetical methods of producing random digits is,
|
||||||
|
* of course, in a state of sin. -- John von Neumann
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct s390_prng_data {
|
||||||
|
unsigned long count; /* how many bytes were produced */
|
||||||
|
char *buf;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct s390_prng_data *p;
|
||||||
|
|
||||||
|
/* copied from libica, use a non-zero initial parameter block */
|
||||||
|
static unsigned char parm_block[32] = {
|
||||||
|
0x0F,0x2B,0x8E,0x63,0x8C,0x8E,0xD2,0x52,0x64,0xB7,0xA0,0x7B,0x75,0x28,0xB8,0xF4,
|
||||||
|
0x75,0x5F,0xD2,0xA6,0x8D,0x97,0x11,0xFF,0x49,0xD8,0x23,0xF3,0x7E,0x21,0xEC,0xA0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int prng_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return nonseekable_open(inode, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prng_add_entropy(void)
|
||||||
|
{
|
||||||
|
__u64 entropy[4];
|
||||||
|
unsigned int i;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
ret = crypt_s390_kmc(KMC_PRNG, parm_block, (char *)entropy,
|
||||||
|
(char *)entropy, sizeof(entropy));
|
||||||
|
BUG_ON(ret < 0 || ret != sizeof(entropy));
|
||||||
|
memcpy(parm_block, entropy, sizeof(entropy));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void prng_seed(int nbytes)
|
||||||
|
{
|
||||||
|
char buf[16];
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
BUG_ON(nbytes > 16);
|
||||||
|
get_random_bytes(buf, nbytes);
|
||||||
|
|
||||||
|
/* Add the entropy */
|
||||||
|
while (nbytes >= 8) {
|
||||||
|
*((__u64 *)parm_block) ^= *((__u64 *)buf+i*8);
|
||||||
|
prng_add_entropy();
|
||||||
|
i += 8;
|
||||||
|
nbytes -= 8;
|
||||||
|
}
|
||||||
|
prng_add_entropy();
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
|
||||||
|
loff_t *ppos)
|
||||||
|
{
|
||||||
|
int chunk, n;
|
||||||
|
int ret = 0;
|
||||||
|
int tmp;
|
||||||
|
|
||||||
|
/* nbytes can be arbitrary long, we spilt it into chunks */
|
||||||
|
while (nbytes) {
|
||||||
|
/* same as in extract_entropy_user in random.c */
|
||||||
|
if (need_resched()) {
|
||||||
|
if (signal_pending(current)) {
|
||||||
|
if (ret == 0)
|
||||||
|
ret = -ERESTARTSYS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* we lose some random bytes if an attacker issues
|
||||||
|
* reads < 8 bytes, but we don't care
|
||||||
|
*/
|
||||||
|
chunk = min_t(int, nbytes, prng_chunk_size);
|
||||||
|
|
||||||
|
/* PRNG only likes multiples of 8 bytes */
|
||||||
|
n = (chunk + 7) & -8;
|
||||||
|
|
||||||
|
if (p->count > prng_entropy_limit)
|
||||||
|
prng_seed(8);
|
||||||
|
|
||||||
|
/* if the CPU supports PRNG stckf is present too */
|
||||||
|
asm volatile(".insn s,0xb27c0000,%0"
|
||||||
|
: "=m" (*((unsigned long long *)p->buf)) : : "cc");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Beside the STCKF the input for the TDES-EDE is the output
|
||||||
|
* of the last operation. We differ here from X9.17 since we
|
||||||
|
* only store one timestamp into the buffer. Padding the whole
|
||||||
|
* buffer with timestamps does not improve security, since
|
||||||
|
* successive stckf have nearly constant offsets.
|
||||||
|
* If an attacker knows the first timestamp it would be
|
||||||
|
* trivial to guess the additional values. One timestamp
|
||||||
|
* is therefore enough and still guarantees unique input values.
|
||||||
|
*
|
||||||
|
* Note: you can still get strict X9.17 conformity by setting
|
||||||
|
* prng_chunk_size to 8 bytes.
|
||||||
|
*/
|
||||||
|
tmp = crypt_s390_kmc(KMC_PRNG, parm_block, p->buf, p->buf, n);
|
||||||
|
BUG_ON((tmp < 0) || (tmp != n));
|
||||||
|
|
||||||
|
p->count += n;
|
||||||
|
|
||||||
|
if (copy_to_user(ubuf, p->buf, chunk))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
nbytes -= chunk;
|
||||||
|
ret += chunk;
|
||||||
|
ubuf += chunk;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct file_operations prng_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.open = &prng_open,
|
||||||
|
.release = NULL,
|
||||||
|
.read = &prng_read,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct miscdevice prng_dev = {
|
||||||
|
.name = "prandom",
|
||||||
|
.minor = MISC_DYNAMIC_MINOR,
|
||||||
|
.fops = &prng_fops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init prng_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* check if the CPU has a PRNG */
|
||||||
|
if (!crypt_s390_func_available(KMC_PRNG))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
if (prng_chunk_size < 8)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
p = kmalloc(sizeof(struct s390_prng_data), GFP_KERNEL);
|
||||||
|
if (!p)
|
||||||
|
return -ENOMEM;
|
||||||
|
p->count = 0;
|
||||||
|
|
||||||
|
p->buf = kmalloc(prng_chunk_size, GFP_KERNEL);
|
||||||
|
if (!p->buf) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize the PRNG, add 128 bits of entropy */
|
||||||
|
prng_seed(16);
|
||||||
|
|
||||||
|
ret = misc_register(&prng_dev);
|
||||||
|
if (ret) {
|
||||||
|
printk(KERN_WARNING
|
||||||
|
"Could not register misc device for PRNG.\n");
|
||||||
|
goto out_buf;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out_buf:
|
||||||
|
kfree(p->buf);
|
||||||
|
out_free:
|
||||||
|
kfree(p);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit prng_exit(void)
|
||||||
|
{
|
||||||
|
/* wipe me */
|
||||||
|
memset(p->buf, 0, prng_chunk_size);
|
||||||
|
kfree(p->buf);
|
||||||
|
kfree(p);
|
||||||
|
|
||||||
|
misc_deregister(&prng_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(prng_init);
|
||||||
|
module_exit(prng_exit);
|
|
@ -8,8 +8,9 @@
|
||||||
* implementation written by Steve Reid.
|
* implementation written by Steve Reid.
|
||||||
*
|
*
|
||||||
* s390 Version:
|
* s390 Version:
|
||||||
* Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
|
* Copyright IBM Corp. 2003,2007
|
||||||
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
|
* Author(s): Thomas Spatzier
|
||||||
|
* Jan Glauber (jan.glauber@de.ibm.com)
|
||||||
*
|
*
|
||||||
* Derived from "crypto/sha1.c"
|
* Derived from "crypto/sha1.c"
|
||||||
* Copyright (c) Alan Smithee.
|
* Copyright (c) Alan Smithee.
|
||||||
|
@ -43,16 +44,14 @@ struct crypt_s390_sha1_ctx {
|
||||||
static void sha1_init(struct crypto_tfm *tfm)
|
static void sha1_init(struct crypto_tfm *tfm)
|
||||||
{
|
{
|
||||||
struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm);
|
struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||||
static const u32 initstate[5] = {
|
|
||||||
0x67452301,
|
ctx->state[0] = 0x67452301;
|
||||||
0xEFCDAB89,
|
ctx->state[1] = 0xEFCDAB89;
|
||||||
0x98BADCFE,
|
ctx->state[2] = 0x98BADCFE;
|
||||||
0x10325476,
|
ctx->state[3] = 0x10325476;
|
||||||
0xC3D2E1F0
|
ctx->state[4] = 0xC3D2E1F0;
|
||||||
};
|
|
||||||
|
|
||||||
ctx->count = 0;
|
ctx->count = 0;
|
||||||
memcpy(ctx->state, &initstate, sizeof(initstate));
|
|
||||||
ctx->buf_len = 0;
|
ctx->buf_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,13 +62,13 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
|
||||||
long imd_len;
|
long imd_len;
|
||||||
|
|
||||||
sctx = crypto_tfm_ctx(tfm);
|
sctx = crypto_tfm_ctx(tfm);
|
||||||
sctx->count += len * 8; //message bit length
|
sctx->count += len * 8; /* message bit length */
|
||||||
|
|
||||||
//anything in buffer yet? -> must be completed
|
/* anything in buffer yet? -> must be completed */
|
||||||
if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) {
|
if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) {
|
||||||
//complete full block and hash
|
/* complete full block and hash */
|
||||||
memcpy(sctx->buffer + sctx->buf_len, data,
|
memcpy(sctx->buffer + sctx->buf_len, data,
|
||||||
SHA1_BLOCK_SIZE - sctx->buf_len);
|
SHA1_BLOCK_SIZE - sctx->buf_len);
|
||||||
crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer,
|
crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer,
|
||||||
SHA1_BLOCK_SIZE);
|
SHA1_BLOCK_SIZE);
|
||||||
data += SHA1_BLOCK_SIZE - sctx->buf_len;
|
data += SHA1_BLOCK_SIZE - sctx->buf_len;
|
||||||
|
@ -77,37 +76,36 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
|
||||||
sctx->buf_len = 0;
|
sctx->buf_len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//rest of data contains full blocks?
|
/* rest of data contains full blocks? */
|
||||||
imd_len = len & ~0x3ful;
|
imd_len = len & ~0x3ful;
|
||||||
if (imd_len){
|
if (imd_len) {
|
||||||
crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len);
|
crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len);
|
||||||
data += imd_len;
|
data += imd_len;
|
||||||
len -= imd_len;
|
len -= imd_len;
|
||||||
}
|
}
|
||||||
//anything left? store in buffer
|
/* anything left? store in buffer */
|
||||||
if (len){
|
if (len) {
|
||||||
memcpy(sctx->buffer + sctx->buf_len , data, len);
|
memcpy(sctx->buffer + sctx->buf_len , data, len);
|
||||||
sctx->buf_len += len;
|
sctx->buf_len += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void pad_message(struct crypt_s390_sha1_ctx* sctx)
|
||||||
pad_message(struct crypt_s390_sha1_ctx* sctx)
|
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
index = sctx->buf_len;
|
index = sctx->buf_len;
|
||||||
sctx->buf_len = (sctx->buf_len < 56)?
|
sctx->buf_len = (sctx->buf_len < 56) ?
|
||||||
SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
|
SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
|
||||||
//start pad with 1
|
/* start pad with 1 */
|
||||||
sctx->buffer[index] = 0x80;
|
sctx->buffer[index] = 0x80;
|
||||||
//pad with zeros
|
/* pad with zeros */
|
||||||
index++;
|
index++;
|
||||||
memset(sctx->buffer + index, 0x00, sctx->buf_len - index);
|
memset(sctx->buffer + index, 0x00, sctx->buf_len - index);
|
||||||
//append length
|
/* append length */
|
||||||
memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count,
|
memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count,
|
||||||
sizeof sctx->count);
|
sizeof sctx->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add padding and return the message digest. */
|
/* Add padding and return the message digest. */
|
||||||
|
@ -115,47 +113,40 @@ static void sha1_final(struct crypto_tfm *tfm, u8 *out)
|
||||||
{
|
{
|
||||||
struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
|
struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
|
||||||
|
|
||||||
//must perform manual padding
|
/* must perform manual padding */
|
||||||
pad_message(sctx);
|
pad_message(sctx);
|
||||||
crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len);
|
crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len);
|
||||||
//copy digest to out
|
/* copy digest to out */
|
||||||
memcpy(out, sctx->state, SHA1_DIGEST_SIZE);
|
memcpy(out, sctx->state, SHA1_DIGEST_SIZE);
|
||||||
/* Wipe context */
|
/* wipe context */
|
||||||
memset(sctx, 0, sizeof *sctx);
|
memset(sctx, 0, sizeof *sctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct crypto_alg alg = {
|
static struct crypto_alg alg = {
|
||||||
.cra_name = "sha1",
|
.cra_name = "sha1",
|
||||||
.cra_driver_name = "sha1-s390",
|
.cra_driver_name= "sha1-s390",
|
||||||
.cra_priority = CRYPT_S390_PRIORITY,
|
.cra_priority = CRYPT_S390_PRIORITY,
|
||||||
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
|
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
|
||||||
.cra_blocksize = SHA1_BLOCK_SIZE,
|
.cra_blocksize = SHA1_BLOCK_SIZE,
|
||||||
.cra_ctxsize = sizeof(struct crypt_s390_sha1_ctx),
|
.cra_ctxsize = sizeof(struct crypt_s390_sha1_ctx),
|
||||||
.cra_module = THIS_MODULE,
|
.cra_module = THIS_MODULE,
|
||||||
.cra_list = LIST_HEAD_INIT(alg.cra_list),
|
.cra_list = LIST_HEAD_INIT(alg.cra_list),
|
||||||
.cra_u = { .digest = {
|
.cra_u = { .digest = {
|
||||||
.dia_digestsize = SHA1_DIGEST_SIZE,
|
.dia_digestsize = SHA1_DIGEST_SIZE,
|
||||||
.dia_init = sha1_init,
|
.dia_init = sha1_init,
|
||||||
.dia_update = sha1_update,
|
.dia_update = sha1_update,
|
||||||
.dia_final = sha1_final } }
|
.dia_final = sha1_final } }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int __init init(void)
|
||||||
init(void)
|
|
||||||
{
|
{
|
||||||
int ret = -ENOSYS;
|
if (!crypt_s390_func_available(KIMD_SHA_1))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
if (crypt_s390_func_available(KIMD_SHA_1)){
|
return crypto_register_alg(&alg);
|
||||||
ret = crypto_register_alg(&alg);
|
|
||||||
if (ret == 0){
|
|
||||||
printk(KERN_INFO "crypt_s390: sha1_s390 loaded.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit
|
static void __exit fini(void)
|
||||||
fini(void)
|
|
||||||
{
|
{
|
||||||
crypto_unregister_alg(&alg);
|
crypto_unregister_alg(&alg);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* s390 implementation of the SHA256 Secure Hash Algorithm.
|
* s390 implementation of the SHA256 Secure Hash Algorithm.
|
||||||
*
|
*
|
||||||
* s390 Version:
|
* s390 Version:
|
||||||
* Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation
|
* Copyright IBM Corp. 2005,2007
|
||||||
* Author(s): Jan Glauber (jang@de.ibm.com)
|
* Author(s): Jan Glauber (jang@de.ibm.com)
|
||||||
*
|
*
|
||||||
* Derived from "crypto/sha256.c"
|
* Derived from "crypto/sha256.c"
|
||||||
|
@ -143,15 +143,10 @@ static struct crypto_alg alg = {
|
||||||
|
|
||||||
static int init(void)
|
static int init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!crypt_s390_func_available(KIMD_SHA_256))
|
if (!crypt_s390_func_available(KIMD_SHA_256))
|
||||||
return -ENOSYS;
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
ret = crypto_register_alg(&alg);
|
return crypto_register_alg(&alg);
|
||||||
if (ret != 0)
|
|
||||||
printk(KERN_INFO "crypt_s390: sha256_s390 couldn't be loaded.");
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit fini(void)
|
static void __exit fini(void)
|
||||||
|
|
|
@ -108,6 +108,8 @@ CONFIG_DEFAULT_MIGRATION_COST=1000000
|
||||||
CONFIG_COMPAT=y
|
CONFIG_COMPAT=y
|
||||||
CONFIG_SYSVIPC_COMPAT=y
|
CONFIG_SYSVIPC_COMPAT=y
|
||||||
CONFIG_AUDIT_ARCH=y
|
CONFIG_AUDIT_ARCH=y
|
||||||
|
CONFIG_S390_SWITCH_AMODE=y
|
||||||
|
CONFIG_S390_EXEC_PROTECT=y
|
||||||
|
|
||||||
#
|
#
|
||||||
# Code generation options
|
# Code generation options
|
||||||
|
@ -431,7 +433,6 @@ CONFIG_TN3270_CONSOLE=y
|
||||||
CONFIG_TN3215=y
|
CONFIG_TN3215=y
|
||||||
CONFIG_TN3215_CONSOLE=y
|
CONFIG_TN3215_CONSOLE=y
|
||||||
CONFIG_CCW_CONSOLE=y
|
CONFIG_CCW_CONSOLE=y
|
||||||
CONFIG_SCLP=y
|
|
||||||
CONFIG_SCLP_TTY=y
|
CONFIG_SCLP_TTY=y
|
||||||
CONFIG_SCLP_CONSOLE=y
|
CONFIG_SCLP_CONSOLE=y
|
||||||
CONFIG_SCLP_VT220_TTY=y
|
CONFIG_SCLP_VT220_TTY=y
|
||||||
|
@ -724,9 +725,7 @@ CONFIG_CRYPTO_MANAGER=y
|
||||||
# CONFIG_CRYPTO_MD4 is not set
|
# CONFIG_CRYPTO_MD4 is not set
|
||||||
# CONFIG_CRYPTO_MD5 is not set
|
# CONFIG_CRYPTO_MD5 is not set
|
||||||
# CONFIG_CRYPTO_SHA1 is not set
|
# CONFIG_CRYPTO_SHA1 is not set
|
||||||
# CONFIG_CRYPTO_SHA1_S390 is not set
|
|
||||||
# CONFIG_CRYPTO_SHA256 is not set
|
# CONFIG_CRYPTO_SHA256 is not set
|
||||||
# CONFIG_CRYPTO_SHA256_S390 is not set
|
|
||||||
# CONFIG_CRYPTO_SHA512 is not set
|
# CONFIG_CRYPTO_SHA512 is not set
|
||||||
# CONFIG_CRYPTO_WP512 is not set
|
# CONFIG_CRYPTO_WP512 is not set
|
||||||
# CONFIG_CRYPTO_TGR192 is not set
|
# CONFIG_CRYPTO_TGR192 is not set
|
||||||
|
@ -735,12 +734,10 @@ CONFIG_CRYPTO_ECB=m
|
||||||
CONFIG_CRYPTO_CBC=y
|
CONFIG_CRYPTO_CBC=y
|
||||||
# CONFIG_CRYPTO_LRW is not set
|
# CONFIG_CRYPTO_LRW is not set
|
||||||
# CONFIG_CRYPTO_DES is not set
|
# CONFIG_CRYPTO_DES is not set
|
||||||
# CONFIG_CRYPTO_DES_S390 is not set
|
|
||||||
# CONFIG_CRYPTO_BLOWFISH is not set
|
# CONFIG_CRYPTO_BLOWFISH is not set
|
||||||
# CONFIG_CRYPTO_TWOFISH is not set
|
# CONFIG_CRYPTO_TWOFISH is not set
|
||||||
# CONFIG_CRYPTO_SERPENT is not set
|
# CONFIG_CRYPTO_SERPENT is not set
|
||||||
# CONFIG_CRYPTO_AES is not set
|
# CONFIG_CRYPTO_AES is not set
|
||||||
# CONFIG_CRYPTO_AES_S390 is not set
|
|
||||||
# CONFIG_CRYPTO_CAST5 is not set
|
# CONFIG_CRYPTO_CAST5 is not set
|
||||||
# CONFIG_CRYPTO_CAST6 is not set
|
# CONFIG_CRYPTO_CAST6 is not set
|
||||||
# CONFIG_CRYPTO_TEA is not set
|
# CONFIG_CRYPTO_TEA is not set
|
||||||
|
@ -755,6 +752,11 @@ CONFIG_CRYPTO_CBC=y
|
||||||
#
|
#
|
||||||
# Hardware crypto devices
|
# Hardware crypto devices
|
||||||
#
|
#
|
||||||
|
# CONFIG_CRYPTO_SHA1_S390 is not set
|
||||||
|
# CONFIG_CRYPTO_SHA256_S390 is not set
|
||||||
|
# CONFIG_CRYPTO_DES_S390 is not set
|
||||||
|
# CONFIG_CRYPTO_AES_S390 is not set
|
||||||
|
CONFIG_S390_PRNG=m
|
||||||
|
|
||||||
#
|
#
|
||||||
# Library routines
|
# Library routines
|
||||||
|
|
|
@ -4,4 +4,4 @@
|
||||||
|
|
||||||
obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
|
obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
|
||||||
|
|
||||||
s390_hypfs-objs := inode.o hypfs_diag.o
|
s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o
|
||||||
|
|
|
@ -27,4 +27,13 @@ extern struct dentry *hypfs_create_str(struct super_block *sb,
|
||||||
struct dentry *dir, const char *name,
|
struct dentry *dir, const char *name,
|
||||||
char *string);
|
char *string);
|
||||||
|
|
||||||
|
/* LPAR Hypervisor */
|
||||||
|
extern int hypfs_diag_init(void);
|
||||||
|
extern void hypfs_diag_exit(void);
|
||||||
|
extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
|
||||||
|
|
||||||
|
/* VM Hypervisor */
|
||||||
|
extern int hypfs_vm_init(void);
|
||||||
|
extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root);
|
||||||
|
|
||||||
#endif /* _HYPFS_H_ */
|
#endif /* _HYPFS_H_ */
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
/*
|
|
||||||
* arch/s390/hypfs_diag.h
|
|
||||||
* Hypervisor filesystem for Linux on s390.
|
|
||||||
*
|
|
||||||
* Copyright (C) IBM Corp. 2006
|
|
||||||
* Author(s): Michael Holzheu <holzheu@de.ibm.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _HYPFS_DIAG_H_
|
|
||||||
#define _HYPFS_DIAG_H_
|
|
||||||
|
|
||||||
extern int hypfs_diag_init(void);
|
|
||||||
extern void hypfs_diag_exit(void);
|
|
||||||
extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
|
|
||||||
|
|
||||||
#endif /* _HYPFS_DIAG_H_ */
|
|
231
arch/s390/hypfs/hypfs_vm.c
Normal file
231
arch/s390/hypfs/hypfs_vm.c
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
/*
|
||||||
|
* Hypervisor filesystem for Linux on s390. z/VM implementation.
|
||||||
|
*
|
||||||
|
* Copyright (C) IBM Corp. 2006
|
||||||
|
* Author(s): Michael Holzheu <holzheu@de.ibm.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
#include <asm/ebcdic.h>
|
||||||
|
#include "hypfs.h"
|
||||||
|
|
||||||
|
#define NAME_LEN 8
|
||||||
|
|
||||||
|
static char local_guest[] = " ";
|
||||||
|
static char all_guests[] = "* ";
|
||||||
|
static char *guest_query;
|
||||||
|
|
||||||
|
struct diag2fc_data {
|
||||||
|
__u32 version;
|
||||||
|
__u32 flags;
|
||||||
|
__u64 used_cpu;
|
||||||
|
__u64 el_time;
|
||||||
|
__u64 mem_min_kb;
|
||||||
|
__u64 mem_max_kb;
|
||||||
|
__u64 mem_share_kb;
|
||||||
|
__u64 mem_used_kb;
|
||||||
|
__u32 pcpus;
|
||||||
|
__u32 lcpus;
|
||||||
|
__u32 vcpus;
|
||||||
|
__u32 cpu_min;
|
||||||
|
__u32 cpu_max;
|
||||||
|
__u32 cpu_shares;
|
||||||
|
__u32 cpu_use_samp;
|
||||||
|
__u32 cpu_delay_samp;
|
||||||
|
__u32 page_wait_samp;
|
||||||
|
__u32 idle_samp;
|
||||||
|
__u32 other_samp;
|
||||||
|
__u32 total_samp;
|
||||||
|
char guest_name[NAME_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct diag2fc_parm_list {
|
||||||
|
char userid[NAME_LEN];
|
||||||
|
char aci_grp[NAME_LEN];
|
||||||
|
__u64 addr;
|
||||||
|
__u32 size;
|
||||||
|
__u32 fmt;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int diag2fc(int size, char* query, void *addr)
|
||||||
|
{
|
||||||
|
unsigned long residual_cnt;
|
||||||
|
unsigned long rc;
|
||||||
|
struct diag2fc_parm_list parm_list;
|
||||||
|
|
||||||
|
memcpy(parm_list.userid, query, NAME_LEN);
|
||||||
|
ASCEBC(parm_list.userid, NAME_LEN);
|
||||||
|
parm_list.addr = (unsigned long) addr ;
|
||||||
|
parm_list.size = size;
|
||||||
|
parm_list.fmt = 0x02;
|
||||||
|
memset(parm_list.aci_grp, 0x40, NAME_LEN);
|
||||||
|
rc = -1;
|
||||||
|
|
||||||
|
asm volatile(
|
||||||
|
" diag %0,%1,0x2fc\n"
|
||||||
|
"0:\n"
|
||||||
|
EX_TABLE(0b,0b)
|
||||||
|
: "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
|
||||||
|
|
||||||
|
if ((rc != 0 ) && (rc != -2))
|
||||||
|
return rc;
|
||||||
|
else
|
||||||
|
return -residual_cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct diag2fc_data *diag2fc_store(char *query, int *count)
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
struct diag2fc_data *data;
|
||||||
|
|
||||||
|
do {
|
||||||
|
size = diag2fc(0, query, NULL);
|
||||||
|
if (size < 0)
|
||||||
|
return ERR_PTR(-EACCES);
|
||||||
|
data = vmalloc(size);
|
||||||
|
if (!data)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
if (diag2fc(size, query, data) == 0)
|
||||||
|
break;
|
||||||
|
vfree(data);
|
||||||
|
} while (1);
|
||||||
|
*count = (size / sizeof(*data));
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void diag2fc_free(void *data)
|
||||||
|
{
|
||||||
|
vfree(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ATTRIBUTE(sb, dir, name, member) \
|
||||||
|
do { \
|
||||||
|
void *rc; \
|
||||||
|
rc = hypfs_create_u64(sb, dir, name, member); \
|
||||||
|
if (IS_ERR(rc)) \
|
||||||
|
return PTR_ERR(rc); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
static int hpyfs_vm_create_guest(struct super_block *sb,
|
||||||
|
struct dentry *systems_dir,
|
||||||
|
struct diag2fc_data *data)
|
||||||
|
{
|
||||||
|
char guest_name[NAME_LEN + 1] = {};
|
||||||
|
struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
|
||||||
|
int dedicated_flag, capped_value;
|
||||||
|
|
||||||
|
capped_value = (data->flags & 0x00000006) >> 1;
|
||||||
|
dedicated_flag = (data->flags & 0x00000008) >> 3;
|
||||||
|
|
||||||
|
/* guest dir */
|
||||||
|
memcpy(guest_name, data->guest_name, NAME_LEN);
|
||||||
|
EBCASC(guest_name, NAME_LEN);
|
||||||
|
strstrip(guest_name);
|
||||||
|
guest_dir = hypfs_mkdir(sb, systems_dir, guest_name);
|
||||||
|
if (IS_ERR(guest_dir))
|
||||||
|
return PTR_ERR(guest_dir);
|
||||||
|
ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time);
|
||||||
|
|
||||||
|
/* logical cpu information */
|
||||||
|
cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus");
|
||||||
|
if (IS_ERR(cpus_dir))
|
||||||
|
return PTR_ERR(cpus_dir);
|
||||||
|
ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu);
|
||||||
|
ATTRIBUTE(sb, cpus_dir, "capped", capped_value);
|
||||||
|
ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag);
|
||||||
|
ATTRIBUTE(sb, cpus_dir, "count", data->vcpus);
|
||||||
|
ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min);
|
||||||
|
ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max);
|
||||||
|
ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares);
|
||||||
|
|
||||||
|
/* memory information */
|
||||||
|
mem_dir = hypfs_mkdir(sb, guest_dir, "mem");
|
||||||
|
if (IS_ERR(mem_dir))
|
||||||
|
return PTR_ERR(mem_dir);
|
||||||
|
ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb);
|
||||||
|
ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb);
|
||||||
|
ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb);
|
||||||
|
ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb);
|
||||||
|
|
||||||
|
/* samples */
|
||||||
|
samples_dir = hypfs_mkdir(sb, guest_dir, "samples");
|
||||||
|
if (IS_ERR(samples_dir))
|
||||||
|
return PTR_ERR(samples_dir);
|
||||||
|
ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp);
|
||||||
|
ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp);
|
||||||
|
ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp);
|
||||||
|
ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp);
|
||||||
|
ATTRIBUTE(sb, samples_dir, "other", data->other_samp);
|
||||||
|
ATTRIBUTE(sb, samples_dir, "total", data->total_samp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hypfs_vm_create_files(struct super_block *sb, struct dentry *root)
|
||||||
|
{
|
||||||
|
struct dentry *dir, *file;
|
||||||
|
struct diag2fc_data *data;
|
||||||
|
int rc, i, count = 0;
|
||||||
|
|
||||||
|
data = diag2fc_store(guest_query, &count);
|
||||||
|
if (IS_ERR(data))
|
||||||
|
return PTR_ERR(data);
|
||||||
|
|
||||||
|
/* Hpervisor Info */
|
||||||
|
dir = hypfs_mkdir(sb, root, "hyp");
|
||||||
|
if (IS_ERR(dir)) {
|
||||||
|
rc = PTR_ERR(dir);
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor");
|
||||||
|
if (IS_ERR(file)) {
|
||||||
|
rc = PTR_ERR(file);
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* physical cpus */
|
||||||
|
dir = hypfs_mkdir(sb, root, "cpus");
|
||||||
|
if (IS_ERR(dir)) {
|
||||||
|
rc = PTR_ERR(dir);
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
file = hypfs_create_u64(sb, dir, "count", data->lcpus);
|
||||||
|
if (IS_ERR(file)) {
|
||||||
|
rc = PTR_ERR(file);
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* guests */
|
||||||
|
dir = hypfs_mkdir(sb, root, "systems");
|
||||||
|
if (IS_ERR(dir)) {
|
||||||
|
rc = PTR_ERR(dir);
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
rc = hpyfs_vm_create_guest(sb, dir, &(data[i]));
|
||||||
|
if (rc)
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
diag2fc_free(data);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
diag2fc_free(data);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int hypfs_vm_init(void)
|
||||||
|
{
|
||||||
|
if (diag2fc(0, all_guests, NULL) > 0)
|
||||||
|
guest_query = all_guests;
|
||||||
|
else if (diag2fc(0, local_guest, NULL) > 0)
|
||||||
|
guest_query = local_guest;
|
||||||
|
else
|
||||||
|
return -EACCES;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -19,7 +19,6 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <asm/ebcdic.h>
|
#include <asm/ebcdic.h>
|
||||||
#include "hypfs.h"
|
#include "hypfs.h"
|
||||||
#include "hypfs_diag.h"
|
|
||||||
|
|
||||||
#define HYPFS_MAGIC 0x687970 /* ASCII 'hyp' */
|
#define HYPFS_MAGIC 0x687970 /* ASCII 'hyp' */
|
||||||
#define TMP_SIZE 64 /* size of temporary buffers */
|
#define TMP_SIZE 64 /* size of temporary buffers */
|
||||||
|
@ -192,7 +191,10 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
hypfs_delete_tree(sb->s_root);
|
hypfs_delete_tree(sb->s_root);
|
||||||
rc = hypfs_diag_create_files(sb, sb->s_root);
|
if (MACHINE_IS_VM)
|
||||||
|
rc = hypfs_vm_create_files(sb, sb->s_root);
|
||||||
|
else
|
||||||
|
rc = hypfs_diag_create_files(sb, sb->s_root);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
printk(KERN_ERR "hypfs: Update failed\n");
|
printk(KERN_ERR "hypfs: Update failed\n");
|
||||||
hypfs_delete_tree(sb->s_root);
|
hypfs_delete_tree(sb->s_root);
|
||||||
|
@ -289,7 +291,10 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto err_alloc;
|
goto err_alloc;
|
||||||
}
|
}
|
||||||
rc = hypfs_diag_create_files(sb, root_dentry);
|
if (MACHINE_IS_VM)
|
||||||
|
rc = hypfs_vm_create_files(sb, root_dentry);
|
||||||
|
else
|
||||||
|
rc = hypfs_diag_create_files(sb, root_dentry);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err_tree;
|
goto err_tree;
|
||||||
sbi->update_file = hypfs_create_update_file(sb, root_dentry);
|
sbi->update_file = hypfs_create_update_file(sb, root_dentry);
|
||||||
|
@ -462,11 +467,15 @@ static int __init hypfs_init(void)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (MACHINE_IS_VM)
|
if (MACHINE_IS_VM) {
|
||||||
return -ENODATA;
|
if (hypfs_vm_init())
|
||||||
if (hypfs_diag_init()) {
|
/* no diag 2fc, just exit */
|
||||||
rc = -ENODATA;
|
return -ENODATA;
|
||||||
goto fail_diag;
|
} else {
|
||||||
|
if (hypfs_diag_init()) {
|
||||||
|
rc = -ENODATA;
|
||||||
|
goto fail_diag;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
kset_set_kset_s(&s390_subsys, hypervisor_subsys);
|
kset_set_kset_s(&s390_subsys, hypervisor_subsys);
|
||||||
rc = subsystem_register(&s390_subsys);
|
rc = subsystem_register(&s390_subsys);
|
||||||
|
@ -480,7 +489,8 @@ static int __init hypfs_init(void)
|
||||||
fail_filesystem:
|
fail_filesystem:
|
||||||
subsystem_unregister(&s390_subsys);
|
subsystem_unregister(&s390_subsys);
|
||||||
fail_sysfs:
|
fail_sysfs:
|
||||||
hypfs_diag_exit();
|
if (!MACHINE_IS_VM)
|
||||||
|
hypfs_diag_exit();
|
||||||
fail_diag:
|
fail_diag:
|
||||||
printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
|
printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -488,7 +498,8 @@ fail_diag:
|
||||||
|
|
||||||
static void __exit hypfs_exit(void)
|
static void __exit hypfs_exit(void)
|
||||||
{
|
{
|
||||||
hypfs_diag_exit();
|
if (!MACHINE_IS_VM)
|
||||||
|
hypfs_diag_exit();
|
||||||
unregister_filesystem(&hypfs_type);
|
unregister_filesystem(&hypfs_type);
|
||||||
subsystem_unregister(&s390_subsys);
|
subsystem_unregister(&s390_subsys);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
|
|
||||||
EXTRA_AFLAGS := -traditional
|
EXTRA_AFLAGS := -traditional
|
||||||
|
|
||||||
obj-y := bitmap.o traps.o time.o process.o reset.o \
|
obj-y := bitmap.o traps.o time.o process.o base.o early.o \
|
||||||
setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.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 ipl.o
|
semaphore.o s390_ext.o debug.o irq.o ipl.o
|
||||||
|
|
||||||
obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
|
obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
|
||||||
obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
|
obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
|
||||||
|
|
150
arch/s390/kernel/base.S
Normal file
150
arch/s390/kernel/base.S
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* arch/s390/kernel/base.S
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2006,2007
|
||||||
|
* Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
|
||||||
|
* Michael Holzheu <holzheu@de.ibm.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <asm/ptrace.h>
|
||||||
|
#include <asm/lowcore.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_64BIT
|
||||||
|
|
||||||
|
.globl s390_base_mcck_handler
|
||||||
|
s390_base_mcck_handler:
|
||||||
|
basr %r13,0
|
||||||
|
0: lg %r15,__LC_PANIC_STACK # load panic stack
|
||||||
|
aghi %r15,-STACK_FRAME_OVERHEAD
|
||||||
|
larl %r1,s390_base_mcck_handler_fn
|
||||||
|
lg %r1,0(%r1)
|
||||||
|
ltgr %r1,%r1
|
||||||
|
jz 1f
|
||||||
|
basr %r14,%r1
|
||||||
|
1: la %r1,4095
|
||||||
|
lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
|
||||||
|
lpswe __LC_MCK_OLD_PSW
|
||||||
|
|
||||||
|
.section .bss
|
||||||
|
.globl s390_base_mcck_handler_fn
|
||||||
|
s390_base_mcck_handler_fn:
|
||||||
|
.quad 0
|
||||||
|
.previous
|
||||||
|
|
||||||
|
.globl s390_base_ext_handler
|
||||||
|
s390_base_ext_handler:
|
||||||
|
stmg %r0,%r15,__LC_SAVE_AREA
|
||||||
|
basr %r13,0
|
||||||
|
0: aghi %r15,-STACK_FRAME_OVERHEAD
|
||||||
|
larl %r1,s390_base_ext_handler_fn
|
||||||
|
lg %r1,0(%r1)
|
||||||
|
ltgr %r1,%r1
|
||||||
|
jz 1f
|
||||||
|
basr %r14,%r1
|
||||||
|
1: lmg %r0,%r15,__LC_SAVE_AREA
|
||||||
|
ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit
|
||||||
|
lpswe __LC_EXT_OLD_PSW
|
||||||
|
|
||||||
|
.section .bss
|
||||||
|
.globl s390_base_ext_handler_fn
|
||||||
|
s390_base_ext_handler_fn:
|
||||||
|
.quad 0
|
||||||
|
.previous
|
||||||
|
|
||||||
|
.globl s390_base_pgm_handler
|
||||||
|
s390_base_pgm_handler:
|
||||||
|
stmg %r0,%r15,__LC_SAVE_AREA
|
||||||
|
basr %r13,0
|
||||||
|
0: aghi %r15,-STACK_FRAME_OVERHEAD
|
||||||
|
larl %r1,s390_base_pgm_handler_fn
|
||||||
|
lg %r1,0(%r1)
|
||||||
|
ltgr %r1,%r1
|
||||||
|
jz 1f
|
||||||
|
basr %r14,%r1
|
||||||
|
lmg %r0,%r15,__LC_SAVE_AREA
|
||||||
|
lpswe __LC_PGM_OLD_PSW
|
||||||
|
1: lpswe disabled_wait_psw-0b(%r13)
|
||||||
|
|
||||||
|
.align 8
|
||||||
|
disabled_wait_psw:
|
||||||
|
.quad 0x0002000180000000,0x0000000000000000 + s390_base_pgm_handler
|
||||||
|
|
||||||
|
.section .bss
|
||||||
|
.globl s390_base_pgm_handler_fn
|
||||||
|
s390_base_pgm_handler_fn:
|
||||||
|
.quad 0
|
||||||
|
.previous
|
||||||
|
|
||||||
|
#else /* CONFIG_64BIT */
|
||||||
|
|
||||||
|
.globl s390_base_mcck_handler
|
||||||
|
s390_base_mcck_handler:
|
||||||
|
basr %r13,0
|
||||||
|
0: l %r15,__LC_PANIC_STACK # load panic stack
|
||||||
|
ahi %r15,-STACK_FRAME_OVERHEAD
|
||||||
|
l %r1,2f-0b(%r13)
|
||||||
|
l %r1,0(%r1)
|
||||||
|
ltr %r1,%r1
|
||||||
|
jz 1f
|
||||||
|
basr %r14,%r1
|
||||||
|
1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA
|
||||||
|
lpsw __LC_MCK_OLD_PSW
|
||||||
|
|
||||||
|
2: .long s390_base_mcck_handler_fn
|
||||||
|
|
||||||
|
.section .bss
|
||||||
|
.globl s390_base_mcck_handler_fn
|
||||||
|
s390_base_mcck_handler_fn:
|
||||||
|
.long 0
|
||||||
|
.previous
|
||||||
|
|
||||||
|
.globl s390_base_ext_handler
|
||||||
|
s390_base_ext_handler:
|
||||||
|
stm %r0,%r15,__LC_SAVE_AREA
|
||||||
|
basr %r13,0
|
||||||
|
0: ahi %r15,-STACK_FRAME_OVERHEAD
|
||||||
|
l %r1,2f-0b(%r13)
|
||||||
|
l %r1,0(%r1)
|
||||||
|
ltr %r1,%r1
|
||||||
|
jz 1f
|
||||||
|
basr %r14,%r1
|
||||||
|
1: lm %r0,%r15,__LC_SAVE_AREA
|
||||||
|
ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit
|
||||||
|
lpsw __LC_EXT_OLD_PSW
|
||||||
|
|
||||||
|
2: .long s390_base_ext_handler_fn
|
||||||
|
|
||||||
|
.section .bss
|
||||||
|
.globl s390_base_ext_handler_fn
|
||||||
|
s390_base_ext_handler_fn:
|
||||||
|
.long 0
|
||||||
|
.previous
|
||||||
|
|
||||||
|
.globl s390_base_pgm_handler
|
||||||
|
s390_base_pgm_handler:
|
||||||
|
stm %r0,%r15,__LC_SAVE_AREA
|
||||||
|
basr %r13,0
|
||||||
|
0: ahi %r15,-STACK_FRAME_OVERHEAD
|
||||||
|
l %r1,2f-0b(%r13)
|
||||||
|
l %r1,0(%r1)
|
||||||
|
ltr %r1,%r1
|
||||||
|
jz 1f
|
||||||
|
basr %r14,%r1
|
||||||
|
lm %r0,%r15,__LC_SAVE_AREA
|
||||||
|
lpsw __LC_PGM_OLD_PSW
|
||||||
|
|
||||||
|
1: lpsw disabled_wait_psw-0b(%r13)
|
||||||
|
|
||||||
|
2: .long s390_base_pgm_handler_fn
|
||||||
|
|
||||||
|
disabled_wait_psw:
|
||||||
|
.align 8
|
||||||
|
.long 0x000a0000,0x00000000 + s390_base_pgm_handler
|
||||||
|
|
||||||
|
.section .bss
|
||||||
|
.globl s390_base_pgm_handler_fn
|
||||||
|
s390_base_pgm_handler_fn:
|
||||||
|
.long 0
|
||||||
|
.previous
|
||||||
|
|
||||||
|
#endif /* CONFIG_64BIT */
|
|
@ -192,7 +192,7 @@ MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>");
|
||||||
|
|
||||||
#undef cputime_to_timeval
|
#undef cputime_to_timeval
|
||||||
#define cputime_to_timeval cputime_to_compat_timeval
|
#define cputime_to_timeval cputime_to_compat_timeval
|
||||||
static __inline__ void
|
static inline void
|
||||||
cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
|
cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
|
||||||
{
|
{
|
||||||
value->tv_usec = cputime % 1000000;
|
value->tv_usec = cputime % 1000000;
|
||||||
|
|
|
@ -12,10 +12,9 @@
|
||||||
#include <linux/personality.h>
|
#include <linux/personality.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
|
||||||
struct exec_domain s390_exec_domain;
|
static struct exec_domain s390_exec_domain;
|
||||||
|
|
||||||
static int __init
|
static int __init s390_init (void)
|
||||||
s390_init (void)
|
|
||||||
{
|
{
|
||||||
s390_exec_domain.name = "Linux/s390";
|
s390_exec_domain.name = "Linux/s390";
|
||||||
s390_exec_domain.handler = NULL;
|
s390_exec_domain.handler = NULL;
|
||||||
|
|
|
@ -69,6 +69,12 @@
|
||||||
|
|
||||||
#include "compat_linux.h"
|
#include "compat_linux.h"
|
||||||
|
|
||||||
|
long psw_user32_bits = (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
|
||||||
|
PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
|
||||||
|
PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
|
||||||
|
long psw32_user_bits = (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME |
|
||||||
|
PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
|
||||||
|
PSW32_MASK_PSTATE);
|
||||||
|
|
||||||
/* For this source file, we want overflow handling. */
|
/* For this source file, we want overflow handling. */
|
||||||
|
|
||||||
|
@ -416,7 +422,7 @@ asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
|
||||||
mm_segment_t old_fs = get_fs ();
|
mm_segment_t old_fs = get_fs ();
|
||||||
|
|
||||||
set_fs (KERNEL_DS);
|
set_fs (KERNEL_DS);
|
||||||
ret = sys_sysinfo((struct sysinfo __user *) &s);
|
ret = sys_sysinfo((struct sysinfo __force __user *) &s);
|
||||||
set_fs (old_fs);
|
set_fs (old_fs);
|
||||||
err = put_user (s.uptime, &info->uptime);
|
err = put_user (s.uptime, &info->uptime);
|
||||||
err |= __put_user (s.loads[0], &info->loads[0]);
|
err |= __put_user (s.loads[0], &info->loads[0]);
|
||||||
|
@ -445,7 +451,8 @@ asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
|
||||||
mm_segment_t old_fs = get_fs ();
|
mm_segment_t old_fs = get_fs ();
|
||||||
|
|
||||||
set_fs (KERNEL_DS);
|
set_fs (KERNEL_DS);
|
||||||
ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t);
|
ret = sys_sched_rr_get_interval(pid,
|
||||||
|
(struct timespec __force __user *) &t);
|
||||||
set_fs (old_fs);
|
set_fs (old_fs);
|
||||||
if (put_compat_timespec(&t, interval))
|
if (put_compat_timespec(&t, interval))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
@ -472,8 +479,8 @@ asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
|
||||||
}
|
}
|
||||||
set_fs (KERNEL_DS);
|
set_fs (KERNEL_DS);
|
||||||
ret = sys_rt_sigprocmask(how,
|
ret = sys_rt_sigprocmask(how,
|
||||||
set ? (sigset_t __user *) &s : NULL,
|
set ? (sigset_t __force __user *) &s : NULL,
|
||||||
oset ? (sigset_t __user *) &s : NULL,
|
oset ? (sigset_t __force __user *) &s : NULL,
|
||||||
sigsetsize);
|
sigsetsize);
|
||||||
set_fs (old_fs);
|
set_fs (old_fs);
|
||||||
if (ret) return ret;
|
if (ret) return ret;
|
||||||
|
@ -499,7 +506,7 @@ asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
|
||||||
mm_segment_t old_fs = get_fs();
|
mm_segment_t old_fs = get_fs();
|
||||||
|
|
||||||
set_fs (KERNEL_DS);
|
set_fs (KERNEL_DS);
|
||||||
ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
|
ret = sys_rt_sigpending((sigset_t __force __user *) &s, sigsetsize);
|
||||||
set_fs (old_fs);
|
set_fs (old_fs);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
switch (_NSIG_WORDS) {
|
switch (_NSIG_WORDS) {
|
||||||
|
@ -524,7 +531,7 @@ sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
|
||||||
if (copy_siginfo_from_user32(&info, uinfo))
|
if (copy_siginfo_from_user32(&info, uinfo))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
set_fs (KERNEL_DS);
|
set_fs (KERNEL_DS);
|
||||||
ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
|
ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *) &info);
|
||||||
set_fs (old_fs);
|
set_fs (old_fs);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -682,7 +689,7 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offse
|
||||||
|
|
||||||
set_fs(KERNEL_DS);
|
set_fs(KERNEL_DS);
|
||||||
ret = sys_sendfile(out_fd, in_fd,
|
ret = sys_sendfile(out_fd, in_fd,
|
||||||
offset ? (off_t __user *) &of : NULL, count);
|
offset ? (off_t __force __user *) &of : NULL, count);
|
||||||
set_fs(old_fs);
|
set_fs(old_fs);
|
||||||
|
|
||||||
if (offset && put_user(of, offset))
|
if (offset && put_user(of, offset))
|
||||||
|
@ -703,7 +710,8 @@ asmlinkage long sys32_sendfile64(int out_fd, int in_fd,
|
||||||
|
|
||||||
set_fs(KERNEL_DS);
|
set_fs(KERNEL_DS);
|
||||||
ret = sys_sendfile64(out_fd, in_fd,
|
ret = sys_sendfile64(out_fd, in_fd,
|
||||||
offset ? (loff_t __user *) &lof : NULL, count);
|
offset ? (loff_t __force __user *) &lof : NULL,
|
||||||
|
count);
|
||||||
set_fs(old_fs);
|
set_fs(old_fs);
|
||||||
|
|
||||||
if (offset && put_user(lof, offset))
|
if (offset && put_user(lof, offset))
|
||||||
|
|
|
@ -115,37 +115,6 @@ typedef struct
|
||||||
__u32 addr;
|
__u32 addr;
|
||||||
} _psw_t32 __attribute__ ((aligned(8)));
|
} _psw_t32 __attribute__ ((aligned(8)));
|
||||||
|
|
||||||
#define PSW32_MASK_PER 0x40000000UL
|
|
||||||
#define PSW32_MASK_DAT 0x04000000UL
|
|
||||||
#define PSW32_MASK_IO 0x02000000UL
|
|
||||||
#define PSW32_MASK_EXT 0x01000000UL
|
|
||||||
#define PSW32_MASK_KEY 0x00F00000UL
|
|
||||||
#define PSW32_MASK_MCHECK 0x00040000UL
|
|
||||||
#define PSW32_MASK_WAIT 0x00020000UL
|
|
||||||
#define PSW32_MASK_PSTATE 0x00010000UL
|
|
||||||
#define PSW32_MASK_ASC 0x0000C000UL
|
|
||||||
#define PSW32_MASK_CC 0x00003000UL
|
|
||||||
#define PSW32_MASK_PM 0x00000f00UL
|
|
||||||
|
|
||||||
#define PSW32_ADDR_AMODE31 0x80000000UL
|
|
||||||
#define PSW32_ADDR_INSN 0x7FFFFFFFUL
|
|
||||||
|
|
||||||
#define PSW32_BASE_BITS 0x00080000UL
|
|
||||||
|
|
||||||
#define PSW32_ASC_PRIMARY 0x00000000UL
|
|
||||||
#define PSW32_ASC_ACCREG 0x00004000UL
|
|
||||||
#define PSW32_ASC_SECONDARY 0x00008000UL
|
|
||||||
#define PSW32_ASC_HOME 0x0000C000UL
|
|
||||||
|
|
||||||
#define PSW32_USER_BITS (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \
|
|
||||||
PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \
|
|
||||||
PSW32_MASK_PSTATE)
|
|
||||||
|
|
||||||
#define PSW32_MASK_MERGE(CURRENT,NEW) \
|
|
||||||
(((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \
|
|
||||||
((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM)))
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
_psw_t32 psw;
|
_psw_t32 psw;
|
||||||
|
|
|
@ -275,8 +275,8 @@ sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss,
|
||||||
}
|
}
|
||||||
|
|
||||||
set_fs (KERNEL_DS);
|
set_fs (KERNEL_DS);
|
||||||
ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL),
|
ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL),
|
||||||
(stack_t __user *) (uoss ? &koss : NULL),
|
(stack_t __force __user *) (uoss ? &koss : NULL),
|
||||||
regs->gprs[15]);
|
regs->gprs[15]);
|
||||||
set_fs (old_fs);
|
set_fs (old_fs);
|
||||||
|
|
||||||
|
@ -298,7 +298,7 @@ static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
|
||||||
_s390_regs_common32 regs32;
|
_s390_regs_common32 regs32;
|
||||||
int err, i;
|
int err, i;
|
||||||
|
|
||||||
regs32.psw.mask = PSW32_MASK_MERGE(PSW32_USER_BITS,
|
regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits,
|
||||||
(__u32)(regs->psw.mask >> 32));
|
(__u32)(regs->psw.mask >> 32));
|
||||||
regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
|
regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
|
||||||
for (i = 0; i < NUM_GPRS; i++)
|
for (i = 0; i < NUM_GPRS; i++)
|
||||||
|
@ -401,7 +401,7 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
|
||||||
goto badframe;
|
goto badframe;
|
||||||
|
|
||||||
set_fs (KERNEL_DS);
|
set_fs (KERNEL_DS);
|
||||||
do_sigaltstack((stack_t __user *)&st, NULL, regs->gprs[15]);
|
do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
|
||||||
set_fs (old_fs);
|
set_fs (old_fs);
|
||||||
|
|
||||||
return regs->gprs[2];
|
return regs->gprs[2];
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <asm/ebcdic.h>
|
#include <asm/ebcdic.h>
|
||||||
#include <asm/cpcmd.h>
|
#include <asm/cpcmd.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
|
#include <asm/io.h>
|
||||||
|
|
||||||
static DEFINE_SPINLOCK(cpcmd_lock);
|
static DEFINE_SPINLOCK(cpcmd_lock);
|
||||||
static char cpcmd_buf[241];
|
static char cpcmd_buf[241];
|
||||||
|
@ -88,13 +89,8 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
|
||||||
int len;
|
int len;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if ((rlen == 0) || (response == NULL)
|
if ((virt_to_phys(response) != (unsigned long) response) ||
|
||||||
|| !((unsigned long)response >> 31)) {
|
(((unsigned long)response + rlen) >> 31)) {
|
||||||
spin_lock_irqsave(&cpcmd_lock, flags);
|
|
||||||
len = __cpcmd(cmd, response, rlen, response_code);
|
|
||||||
spin_unlock_irqrestore(&cpcmd_lock, flags);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
|
lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
|
||||||
if (!lowbuf) {
|
if (!lowbuf) {
|
||||||
printk(KERN_WARNING
|
printk(KERN_WARNING
|
||||||
|
@ -106,6 +102,10 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
|
||||||
spin_unlock_irqrestore(&cpcmd_lock, flags);
|
spin_unlock_irqrestore(&cpcmd_lock, flags);
|
||||||
memcpy(response, lowbuf, rlen);
|
memcpy(response, lowbuf, rlen);
|
||||||
kfree(lowbuf);
|
kfree(lowbuf);
|
||||||
|
} else {
|
||||||
|
spin_lock_irqsave(&cpcmd_lock, flags);
|
||||||
|
len = __cpcmd(cmd, response, rlen, response_code);
|
||||||
|
spin_unlock_irqrestore(&cpcmd_lock, flags);
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include <linux/threads.h>
|
#include <linux/threads.h>
|
||||||
#include <linux/kexec.h>
|
#include <linux/kexec.h>
|
||||||
|
#include <linux/reboot.h>
|
||||||
|
|
||||||
void machine_crash_shutdown(struct pt_regs *regs)
|
void machine_crash_shutdown(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
|
|
@ -120,7 +120,7 @@ struct debug_view debug_hex_ascii_view = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
struct debug_view debug_level_view = {
|
static struct debug_view debug_level_view = {
|
||||||
"level",
|
"level",
|
||||||
&debug_prolog_level_fn,
|
&debug_prolog_level_fn,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -129,7 +129,7 @@ struct debug_view debug_level_view = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
struct debug_view debug_pages_view = {
|
static struct debug_view debug_pages_view = {
|
||||||
"pages",
|
"pages",
|
||||||
&debug_prolog_pages_fn,
|
&debug_prolog_pages_fn,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -138,7 +138,7 @@ struct debug_view debug_pages_view = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
struct debug_view debug_flush_view = {
|
static struct debug_view debug_flush_view = {
|
||||||
"flush",
|
"flush",
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -156,14 +156,14 @@ struct debug_view debug_sprintf_view = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* used by dump analysis tools to determine version of debug feature */
|
||||||
unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
|
unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
|
||||||
|
|
||||||
/* static globals */
|
/* static globals */
|
||||||
|
|
||||||
static debug_info_t *debug_area_first = NULL;
|
static debug_info_t *debug_area_first = NULL;
|
||||||
static debug_info_t *debug_area_last = NULL;
|
static debug_info_t *debug_area_last = NULL;
|
||||||
DECLARE_MUTEX(debug_lock);
|
static DECLARE_MUTEX(debug_lock);
|
||||||
|
|
||||||
static int initialized;
|
static int initialized;
|
||||||
|
|
||||||
|
@ -905,7 +905,7 @@ static struct ctl_table s390dbf_dir_table[] = {
|
||||||
{ .ctl_name = 0 }
|
{ .ctl_name = 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ctl_table_header *s390dbf_sysctl_header;
|
static struct ctl_table_header *s390dbf_sysctl_header;
|
||||||
|
|
||||||
void
|
void
|
||||||
debug_stop_all(void)
|
debug_stop_all(void)
|
||||||
|
@ -1300,8 +1300,7 @@ out:
|
||||||
* flushes debug areas
|
* flushes debug areas
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
static void debug_flush(debug_info_t* id, int area)
|
||||||
debug_flush(debug_info_t* id, int area)
|
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int i,j;
|
int i,j;
|
||||||
|
@ -1511,8 +1510,7 @@ out:
|
||||||
/*
|
/*
|
||||||
* clean up module
|
* clean up module
|
||||||
*/
|
*/
|
||||||
void
|
static void __exit debug_exit(void)
|
||||||
__exit debug_exit(void)
|
|
||||||
{
|
{
|
||||||
debugfs_remove(debug_debugfs_root_entry);
|
debugfs_remove(debug_debugfs_root_entry);
|
||||||
unregister_sysctl_table(s390dbf_sysctl_header);
|
unregister_sysctl_table(s390dbf_sysctl_header);
|
||||||
|
|
306
arch/s390/kernel/early.c
Normal file
306
arch/s390/kernel/early.c
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
/*
|
||||||
|
* arch/s390/kernel/early.c
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2007
|
||||||
|
* Author(s): Hongjie Yang <hongjie@us.ibm.com>,
|
||||||
|
* Heiko Carstens <heiko.carstens@de.ibm.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
#include <linux/lockdep.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/pfn.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <asm/lowcore.h>
|
||||||
|
#include <asm/processor.h>
|
||||||
|
#include <asm/sections.h>
|
||||||
|
#include <asm/setup.h>
|
||||||
|
#include <asm/cpcmd.h>
|
||||||
|
#include <asm/sclp.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a Kernel NSS if the SAVESYS= parameter is defined
|
||||||
|
*/
|
||||||
|
#define DEFSYS_CMD_SIZE 96
|
||||||
|
#define SAVESYS_CMD_SIZE 32
|
||||||
|
|
||||||
|
char kernel_nss_name[NSS_NAME_SIZE + 1];
|
||||||
|
|
||||||
|
#ifdef CONFIG_SHARED_KERNEL
|
||||||
|
static noinline __init void create_kernel_nss(void)
|
||||||
|
{
|
||||||
|
unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
|
||||||
|
#ifdef CONFIG_BLK_DEV_INITRD
|
||||||
|
unsigned int sinitrd_pfn, einitrd_pfn;
|
||||||
|
#endif
|
||||||
|
int response;
|
||||||
|
char *savesys_ptr;
|
||||||
|
char upper_command_line[COMMAND_LINE_SIZE];
|
||||||
|
char defsys_cmd[DEFSYS_CMD_SIZE];
|
||||||
|
char savesys_cmd[SAVESYS_CMD_SIZE];
|
||||||
|
|
||||||
|
/* Do nothing if we are not running under VM */
|
||||||
|
if (!MACHINE_IS_VM)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Convert COMMAND_LINE to upper case */
|
||||||
|
for (i = 0; i < strlen(COMMAND_LINE); i++)
|
||||||
|
upper_command_line[i] = toupper(COMMAND_LINE[i]);
|
||||||
|
|
||||||
|
savesys_ptr = strstr(upper_command_line, "SAVESYS=");
|
||||||
|
|
||||||
|
if (!savesys_ptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
savesys_ptr += 8; /* Point to the beginning of the NSS name */
|
||||||
|
for (i = 0; i < NSS_NAME_SIZE; i++) {
|
||||||
|
if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0')
|
||||||
|
break;
|
||||||
|
kernel_nss_name[i] = savesys_ptr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
stext_pfn = PFN_DOWN(__pa(&_stext));
|
||||||
|
eshared_pfn = PFN_DOWN(__pa(&_eshared));
|
||||||
|
end_pfn = PFN_UP(__pa(&_end));
|
||||||
|
min_size = end_pfn << 2;
|
||||||
|
|
||||||
|
sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
|
||||||
|
kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1,
|
||||||
|
eshared_pfn, end_pfn);
|
||||||
|
|
||||||
|
#ifdef CONFIG_BLK_DEV_INITRD
|
||||||
|
if (INITRD_START && INITRD_SIZE) {
|
||||||
|
sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
|
||||||
|
einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
|
||||||
|
min_size = einitrd_pfn << 2;
|
||||||
|
sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd,
|
||||||
|
sinitrd_pfn, einitrd_pfn);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size);
|
||||||
|
sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
|
||||||
|
kernel_nss_name, kernel_nss_name);
|
||||||
|
|
||||||
|
__cpcmd(defsys_cmd, NULL, 0, &response);
|
||||||
|
|
||||||
|
if (response != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
__cpcmd(savesys_cmd, NULL, 0, &response);
|
||||||
|
|
||||||
|
if (response != strlen(savesys_cmd))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ipl_flags = IPL_NSS_VALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* CONFIG_SHARED_KERNEL */
|
||||||
|
|
||||||
|
static inline void create_kernel_nss(void) { }
|
||||||
|
|
||||||
|
#endif /* CONFIG_SHARED_KERNEL */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear bss memory
|
||||||
|
*/
|
||||||
|
static noinline __init void clear_bss_section(void)
|
||||||
|
{
|
||||||
|
memset(__bss_start, 0, _end - __bss_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize storage key for kernel pages
|
||||||
|
*/
|
||||||
|
static noinline __init void init_kernel_storage_key(void)
|
||||||
|
{
|
||||||
|
unsigned long end_pfn, init_pfn;
|
||||||
|
|
||||||
|
end_pfn = PFN_UP(__pa(&_end));
|
||||||
|
|
||||||
|
for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
|
||||||
|
page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
static noinline __init void detect_machine_type(void)
|
||||||
|
{
|
||||||
|
struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
|
||||||
|
|
||||||
|
asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id));
|
||||||
|
|
||||||
|
/* Running under z/VM ? */
|
||||||
|
if (cpuinfo->cpu_id.version == 0xff)
|
||||||
|
machine_flags |= 1;
|
||||||
|
|
||||||
|
/* Running on a P/390 ? */
|
||||||
|
if (cpuinfo->cpu_id.machine == 0x7490)
|
||||||
|
machine_flags |= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static noinline __init int memory_fast_detect(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned long val0 = 0;
|
||||||
|
unsigned long val1 = 0xc;
|
||||||
|
int ret = -ENOSYS;
|
||||||
|
|
||||||
|
if (ipl_flags & IPL_NSS_VALID)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
asm volatile(
|
||||||
|
" diag %1,%2,0x260\n"
|
||||||
|
"0: lhi %0,0\n"
|
||||||
|
"1:\n"
|
||||||
|
EX_TABLE(0b,1b)
|
||||||
|
: "+d" (ret), "+d" (val0), "+d" (val1) : : "cc");
|
||||||
|
|
||||||
|
if (ret || val0 != val1)
|
||||||
|
return -ENOSYS;
|
||||||
|
|
||||||
|
memory_chunk[0].size = val0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ADDR2G (1UL << 31)
|
||||||
|
|
||||||
|
static noinline __init unsigned long sclp_memory_detect(void)
|
||||||
|
{
|
||||||
|
struct sclp_readinfo_sccb *sccb;
|
||||||
|
unsigned long long memsize;
|
||||||
|
|
||||||
|
sccb = &s390_readinfo_sccb;
|
||||||
|
|
||||||
|
if (sccb->header.response_code != 0x10)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (sccb->rnsize)
|
||||||
|
memsize = sccb->rnsize << 20;
|
||||||
|
else
|
||||||
|
memsize = sccb->rnsize2 << 20;
|
||||||
|
if (sccb->rnmax)
|
||||||
|
memsize *= sccb->rnmax;
|
||||||
|
else
|
||||||
|
memsize *= sccb->rnmax2;
|
||||||
|
#ifndef CONFIG_64BIT
|
||||||
|
/*
|
||||||
|
* Can't deal with more than 2G in 31 bit addressing mode, so
|
||||||
|
* limit the value in order to avoid strange side effects.
|
||||||
|
*/
|
||||||
|
if (memsize > ADDR2G)
|
||||||
|
memsize = ADDR2G;
|
||||||
|
#endif
|
||||||
|
return (unsigned long) memsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __init unsigned long __tprot(unsigned long addr)
|
||||||
|
{
|
||||||
|
int cc = -1;
|
||||||
|
|
||||||
|
asm volatile(
|
||||||
|
" tprot 0(%1),0\n"
|
||||||
|
"0: ipm %0\n"
|
||||||
|
" srl %0,28\n"
|
||||||
|
"1:\n"
|
||||||
|
EX_TABLE(0b,1b)
|
||||||
|
: "+d" (cc) : "a" (addr) : "cc");
|
||||||
|
return (unsigned long)cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Checking memory in 128KB increments. */
|
||||||
|
#define CHUNK_INCR (1UL << 17)
|
||||||
|
|
||||||
|
static noinline __init void find_memory_chunks(unsigned long memsize)
|
||||||
|
{
|
||||||
|
unsigned long addr = 0, old_addr = 0;
|
||||||
|
unsigned long old_cc = CHUNK_READ_WRITE;
|
||||||
|
unsigned long cc;
|
||||||
|
int chunk = 0;
|
||||||
|
|
||||||
|
while (chunk < MEMORY_CHUNKS) {
|
||||||
|
cc = __tprot(addr);
|
||||||
|
while (cc == old_cc) {
|
||||||
|
addr += CHUNK_INCR;
|
||||||
|
cc = __tprot(addr);
|
||||||
|
#ifndef CONFIG_64BIT
|
||||||
|
if (addr == ADDR2G)
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old_addr != addr &&
|
||||||
|
(old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) {
|
||||||
|
memory_chunk[chunk].addr = old_addr;
|
||||||
|
memory_chunk[chunk].size = addr - old_addr;
|
||||||
|
memory_chunk[chunk].type = old_cc;
|
||||||
|
chunk++;
|
||||||
|
}
|
||||||
|
|
||||||
|
old_addr = addr;
|
||||||
|
old_cc = cc;
|
||||||
|
|
||||||
|
#ifndef CONFIG_64BIT
|
||||||
|
if (addr == ADDR2G)
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Finish memory detection at the first hole, unless
|
||||||
|
* - we reached the hsa -> skip it.
|
||||||
|
* - we know there must be more.
|
||||||
|
*/
|
||||||
|
if (cc == -1UL && !memsize && old_addr != ADDR2G)
|
||||||
|
break;
|
||||||
|
if (memsize && addr >= memsize)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static __init void early_pgm_check_handler(void)
|
||||||
|
{
|
||||||
|
unsigned long addr;
|
||||||
|
const struct exception_table_entry *fixup;
|
||||||
|
|
||||||
|
addr = S390_lowcore.program_old_psw.addr;
|
||||||
|
fixup = search_exception_tables(addr & PSW_ADDR_INSN);
|
||||||
|
if (!fixup)
|
||||||
|
disabled_wait(0);
|
||||||
|
S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static noinline __init void setup_lowcore_early(void)
|
||||||
|
{
|
||||||
|
psw_t psw;
|
||||||
|
|
||||||
|
psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
|
||||||
|
psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler;
|
||||||
|
S390_lowcore.external_new_psw = psw;
|
||||||
|
psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
|
||||||
|
S390_lowcore.program_new_psw = psw;
|
||||||
|
s390_base_pgm_handler_fn = early_pgm_check_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save ipl parameters, clear bss memory, initialize storage keys
|
||||||
|
* and create a kernel NSS at startup if the SAVESYS= parm is defined
|
||||||
|
*/
|
||||||
|
void __init startup_init(void)
|
||||||
|
{
|
||||||
|
unsigned long memsize;
|
||||||
|
|
||||||
|
ipl_save_parameters();
|
||||||
|
clear_bss_section();
|
||||||
|
init_kernel_storage_key();
|
||||||
|
lockdep_init();
|
||||||
|
lockdep_off();
|
||||||
|
detect_machine_type();
|
||||||
|
create_kernel_nss();
|
||||||
|
sort_main_extable();
|
||||||
|
setup_lowcore_early();
|
||||||
|
sclp_readinfo_early();
|
||||||
|
memsize = sclp_memory_detect();
|
||||||
|
if (memory_fast_detect() < 0)
|
||||||
|
find_memory_chunks(memsize);
|
||||||
|
lockdep_on();
|
||||||
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
|
#include <asm/ebcdic.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ASCII (IBM PC 437) -> EBCDIC 037
|
* ASCII (IBM PC 437) -> EBCDIC 037
|
||||||
|
|
|
@ -51,175 +51,14 @@ startup_continue:
|
||||||
st %r15,__LC_KERNEL_STACK # set end of kernel stack
|
st %r15,__LC_KERNEL_STACK # set end of kernel stack
|
||||||
ahi %r15,-96
|
ahi %r15,-96
|
||||||
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
|
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
|
||||||
|
#
|
||||||
l %r14,.Lipl_save_parameters-.LPG1(%r13)
|
# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
|
||||||
|
# and create a kernel NSS if the SAVESYS= parm is defined
|
||||||
|
#
|
||||||
|
l %r14,.Lstartup_init-.LPG1(%r13)
|
||||||
basr %r14,%r14
|
basr %r14,%r14
|
||||||
#
|
|
||||||
# clear bss memory
|
|
||||||
#
|
|
||||||
l %r2,.Lbss_bgn-.LPG1(%r13) # start of bss
|
|
||||||
l %r3,.Lbss_end-.LPG1(%r13) # end of bss
|
|
||||||
sr %r3,%r2 # length of bss
|
|
||||||
sr %r4,%r4
|
|
||||||
sr %r5,%r5 # set src,length and pad to zero
|
|
||||||
sr %r0,%r0
|
|
||||||
mvcle %r2,%r4,0 # clear mem
|
|
||||||
jo .-4 # branch back, if not finish
|
|
||||||
|
|
||||||
l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word
|
|
||||||
.Lservicecall:
|
|
||||||
stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts
|
|
||||||
|
|
||||||
stctl %r0, %r0,.Lcr-.LPG1(%r13) # get cr0
|
|
||||||
la %r1,0x200 # set bit 22
|
|
||||||
o %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1
|
|
||||||
st %r1,.Lcr-.LPG1(%r13)
|
|
||||||
lctl %r0, %r0,.Lcr-.LPG1(%r13) # load modified cr0
|
|
||||||
|
|
||||||
mvc __LC_EXT_NEW_PSW(8),.Lpcext-.LPG1(%r13) # set postcall psw
|
|
||||||
la %r1, .Lsclph-.LPG1(%r13)
|
|
||||||
a %r1,__LC_EXT_NEW_PSW+4 # set handler
|
|
||||||
st %r1,__LC_EXT_NEW_PSW+4
|
|
||||||
|
|
||||||
l %r4,.Lsccbaddr-.LPG1(%r13) # %r4 is our index for sccb stuff
|
|
||||||
lr %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)
|
|
||||||
lpsw .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)
|
|
||||||
.Lprocsccb:
|
|
||||||
lhi %r1,0
|
|
||||||
icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
|
|
||||||
jnz .Lscnd
|
|
||||||
lhi %r1,0x800 # otherwise report 2GB
|
|
||||||
.Lscnd:
|
|
||||||
lhi %r3,0x800 # limit reported memory size to 2GB
|
|
||||||
cr %r1,%r3
|
|
||||||
jl .Lno2gb
|
|
||||||
lr %r1,%r3
|
|
||||||
.Lno2gb:
|
|
||||||
xr %r3,%r3 # same logic
|
|
||||||
ic %r3,.Lscpa1-.Lsccb(%r4)
|
|
||||||
chi %r3,0x00
|
|
||||||
jne .Lcompmem
|
|
||||||
l %r3,.Lscpa2-.Lsccb(%r4)
|
|
||||||
.Lcompmem:
|
|
||||||
mr %r2,%r1 # mem in MB on 128-bit
|
|
||||||
l %r1,.Lonemb-.LPG1(%r13)
|
|
||||||
mr %r2,%r1 # mem size in bytes in %r3
|
|
||||||
b .Lfchunk-.LPG1(%r13)
|
|
||||||
|
|
||||||
.align 4
|
|
||||||
.Lipl_save_parameters:
|
|
||||||
.long ipl_save_parameters
|
|
||||||
.Linittu:
|
|
||||||
.long init_thread_union
|
|
||||||
.Lpmask:
|
|
||||||
.byte 0
|
|
||||||
.align 8
|
|
||||||
.Lpcext:.long 0x00080000,0x80000000
|
|
||||||
.Lcr:
|
|
||||||
.long 0x00 # place holder for cr0
|
|
||||||
.align 8
|
|
||||||
.Lwaitsclp:
|
|
||||||
.long 0x010a0000,0x80000000 + .Lsclph
|
|
||||||
.Lrcp:
|
|
||||||
.int 0x00120001 # Read SCP forced code
|
|
||||||
.Lrcp2:
|
|
||||||
.int 0x00020001 # Read SCP code
|
|
||||||
.Lonemb:
|
|
||||||
.int 0x100000
|
|
||||||
.Lfchunk:
|
|
||||||
|
|
||||||
#
|
|
||||||
# find memory chunks.
|
|
||||||
#
|
|
||||||
lr %r9,%r3 # end of mem
|
|
||||||
mvc __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13)
|
|
||||||
la %r1,1 # test in increments of 128KB
|
|
||||||
sll %r1,17
|
|
||||||
l %r3,.Lmchunk-.LPG1(%r13) # get pointer to memory_chunk array
|
|
||||||
slr %r4,%r4 # set start of chunk to zero
|
|
||||||
slr %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
|
|
||||||
be .Lsame-.LPG1(%r13)
|
|
||||||
lhi %r8,0 # no program checks
|
|
||||||
b .Lsavchk-.LPG1(%r13)
|
|
||||||
.Lsame:
|
|
||||||
ar %r5,%r1 # add 128KB to end of chunk
|
|
||||||
bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop
|
|
||||||
.Lchkmem: # > 2GB or tprot got a program check
|
|
||||||
lhi %r8,1 # set program check flag
|
|
||||||
.Lsavchk:
|
|
||||||
clr %r4,%r5 # chunk size > 0?
|
|
||||||
be .Lchkloop-.LPG1(%r13)
|
|
||||||
st %r4,0(%r3) # store start address of chunk
|
|
||||||
lr %r0,%r5
|
|
||||||
slr %r0,%r4
|
|
||||||
st %r0,4(%r3) # store size of chunk
|
|
||||||
st %r6,8(%r3) # store type of chunk
|
|
||||||
la %r3,12(%r3)
|
|
||||||
ahi %r10,-1 # update chunk number
|
|
||||||
.Lchkloop:
|
|
||||||
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
|
|
||||||
xr %r0,%r0
|
|
||||||
clr %r0,%r9 # did we detect memory?
|
|
||||||
je .Ldonemem # if not, leave
|
|
||||||
chi %r10,0 # do we have chunks left?
|
|
||||||
je .Ldonemem
|
|
||||||
chi %r8,1 # program check ?
|
|
||||||
je .Lpgmchk
|
|
||||||
lr %r4,%r5 # potential new chunk
|
|
||||||
alr %r5,%r1 # add 128KB to end of chunk
|
|
||||||
j .Llpcnt
|
|
||||||
.Lpgmchk:
|
|
||||||
alr %r5,%r1 # add 128KB to end of chunk
|
|
||||||
lr %r4,%r5 # potential new chunk
|
|
||||||
.Llpcnt:
|
|
||||||
clr %r5,%r9 # should we go on?
|
|
||||||
jl .Lloop
|
|
||||||
.Ldonemem:
|
|
||||||
l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
|
l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
|
||||||
#
|
|
||||||
# find out if we are running under VM
|
|
||||||
#
|
|
||||||
stidp __LC_CPUID # store cpuid
|
|
||||||
tm __LC_CPUID,0xff # running under VM ?
|
|
||||||
bno .Lnovm-.LPG1(%r13)
|
|
||||||
oi 3(%r12),1 # set VM flag
|
|
||||||
.Lnovm:
|
|
||||||
lh %r0,__LC_CPUID+4 # get cpu version
|
|
||||||
chi %r0,0x7490 # running on a P/390 ?
|
|
||||||
bne .Lnop390-.LPG1(%r13)
|
|
||||||
oi 3(%r12),4 # set P/390 flag
|
|
||||||
.Lnop390:
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# find out if we have an IEEE fpu
|
# find out if we have an IEEE fpu
|
||||||
#
|
#
|
||||||
|
@ -295,7 +134,6 @@ startup_continue:
|
||||||
.long 0 # cr15: linkage stack operations
|
.long 0 # cr15: linkage stack operations
|
||||||
.Lduct: .long 0,0,0,0,0,0,0,0
|
.Lduct: .long 0,0,0,0,0,0,0,0
|
||||||
.long 0,0,0,0,0,0,0,0
|
.long 0,0,0,0,0,0,0,0
|
||||||
.Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem
|
|
||||||
.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu
|
.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu
|
||||||
.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
|
.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
|
||||||
.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
|
.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
|
||||||
|
@ -306,7 +144,9 @@ startup_continue:
|
||||||
.Lbss_bgn: .long __bss_start
|
.Lbss_bgn: .long __bss_start
|
||||||
.Lbss_end: .long _end
|
.Lbss_end: .long _end
|
||||||
.Lparmaddr: .long PARMAREA
|
.Lparmaddr: .long PARMAREA
|
||||||
.Lsccbaddr: .long .Lsccb
|
.Linittu: .long init_thread_union
|
||||||
|
.Lstartup_init:
|
||||||
|
.long startup_init
|
||||||
|
|
||||||
.globl ipl_schib
|
.globl ipl_schib
|
||||||
ipl_schib:
|
ipl_schib:
|
||||||
|
@ -322,26 +162,6 @@ ipl_devno:
|
||||||
.word 0
|
.word 0
|
||||||
|
|
||||||
.org 0x12000
|
.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
|
|
||||||
.Lsccbr:
|
|
||||||
.hword 0x00 # response code
|
|
||||||
.Lscpincr1:
|
|
||||||
.hword 0x00
|
|
||||||
.Lscpa1:
|
|
||||||
.byte 0x00
|
|
||||||
.fill 89,1,0
|
|
||||||
.Lscpa2:
|
|
||||||
.int 0x00
|
|
||||||
.Lscpincr2:
|
|
||||||
.quad 0x00
|
|
||||||
.fill 3984,1,0
|
|
||||||
.org 0x13000
|
|
||||||
|
|
||||||
#ifdef CONFIG_SHARED_KERNEL
|
#ifdef CONFIG_SHARED_KERNEL
|
||||||
.org 0x100000
|
.org 0x100000
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -58,182 +58,14 @@ startup_continue:
|
||||||
stg %r15,__LC_KERNEL_STACK # set end of kernel stack
|
stg %r15,__LC_KERNEL_STACK # set end of kernel stack
|
||||||
aghi %r15,-160
|
aghi %r15,-160
|
||||||
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
|
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
|
||||||
|
|
||||||
brasl %r14,ipl_save_parameters
|
|
||||||
#
|
#
|
||||||
# clear bss memory
|
# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
|
||||||
|
# and create a kernel NSS if the SAVESYS= parm is defined
|
||||||
#
|
#
|
||||||
larl %r2,__bss_start # start of bss segment
|
brasl %r14,startup_init
|
||||||
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
|
|
||||||
# set program check new psw mask
|
# set program check new psw mask
|
||||||
mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
|
mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
|
||||||
larl %r1,.Lslowmemdetect # set program check address
|
|
||||||
stg %r1,__LC_PGM_NEW_PSW+8
|
|
||||||
lghi %r1,0xc
|
|
||||||
diag %r0,%r1,0x260 # get memory size of virtual machine
|
|
||||||
cgr %r0,%r1 # different? -> old detection routine
|
|
||||||
jne .Lslowmemdetect
|
|
||||||
aghi %r1,1 # size is one more than end
|
|
||||||
larl %r2,memory_chunk
|
|
||||||
stg %r1,8(%r2) # store size of chunk
|
|
||||||
j .Ldonemem
|
|
||||||
|
|
||||||
.Lslowmemdetect:
|
|
||||||
l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word
|
|
||||||
.Lservicecall:
|
|
||||||
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
|
|
||||||
|
|
||||||
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)
|
|
||||||
.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)
|
|
||||||
.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
|
|
||||||
.Lscnd:
|
|
||||||
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)
|
|
||||||
|
|
||||||
.align 4
|
|
||||||
.Lpmask:
|
|
||||||
.byte 0
|
|
||||||
.align 8
|
|
||||||
.Lcr:
|
|
||||||
.quad 0x00 # place holder for cr0
|
|
||||||
.Lwaitsclp:
|
|
||||||
.quad 0x0102000180000000,.Lsclph
|
|
||||||
.Lrcp:
|
|
||||||
.int 0x00120001 # Read SCP forced code
|
|
||||||
.Lrcp2:
|
|
||||||
.int 0x00020001 # Read SCP code
|
|
||||||
.Lonemb:
|
|
||||||
.int 0x100000
|
|
||||||
|
|
||||||
.Lfchunk:
|
|
||||||
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
.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
|
|
||||||
lghi %r8,0 # no program checks
|
|
||||||
j .Lsavchk
|
|
||||||
.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
|
|
||||||
lghi %r8,1 # set program check flag
|
|
||||||
.Lsavchk:
|
|
||||||
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)
|
|
||||||
ahi %r10,-1 # update chunk number
|
|
||||||
.Lchkloop:
|
|
||||||
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
|
|
||||||
.Lhsaskip:
|
|
||||||
chi %r8,1 # program check ?
|
|
||||||
je .Lpgmchk
|
|
||||||
lgr %r4,%r5 # potential new chunk
|
|
||||||
algr %r5,%r1 # add 128KB to end of chunk
|
|
||||||
j .Llpcnt
|
|
||||||
.Lpgmchk:
|
|
||||||
algr %r5,%r1 # add 128KB to end of chunk
|
|
||||||
lgr %r4,%r5 # potential new chunk
|
|
||||||
.Llpcnt:
|
|
||||||
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
|
|
||||||
1:
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# find out if we have the MVPG instruction
|
# find out if we have the MVPG instruction
|
||||||
#
|
#
|
||||||
|
@ -336,25 +168,6 @@ ipl_devno:
|
||||||
.word 0
|
.word 0
|
||||||
|
|
||||||
.org 0x12000
|
.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
|
|
||||||
.Lsccbr:
|
|
||||||
.hword 0x00 # response code
|
|
||||||
.Lscpincr1:
|
|
||||||
.hword 0x00
|
|
||||||
.Lscpa1:
|
|
||||||
.byte 0x00
|
|
||||||
.fill 89,1,0
|
|
||||||
.Lscpa2:
|
|
||||||
.int 0x00
|
|
||||||
.Lscpincr2:
|
|
||||||
.quad 0x00
|
|
||||||
.fill 3984,1,0
|
|
||||||
.org 0x13000
|
|
||||||
|
|
||||||
#ifdef CONFIG_SHARED_KERNEL
|
#ifdef CONFIG_SHARED_KERNEL
|
||||||
.org 0x100000
|
.org 0x100000
|
||||||
|
|
|
@ -20,26 +20,27 @@
|
||||||
#include <asm/cio.h>
|
#include <asm/cio.h>
|
||||||
#include <asm/ebcdic.h>
|
#include <asm/ebcdic.h>
|
||||||
#include <asm/reset.h>
|
#include <asm/reset.h>
|
||||||
|
#include <asm/sclp.h>
|
||||||
|
|
||||||
#define IPL_PARM_BLOCK_VERSION 0
|
#define IPL_PARM_BLOCK_VERSION 0
|
||||||
#define LOADPARM_LEN 8
|
|
||||||
|
|
||||||
extern char s390_readinfo_sccb[];
|
#define SCCB_VALID (s390_readinfo_sccb.header.response_code == 0x10)
|
||||||
#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010)
|
#define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm)
|
||||||
#define SCCB_LOADPARM (&s390_readinfo_sccb[24])
|
#define SCCB_FLAG (s390_readinfo_sccb.flags)
|
||||||
#define SCCB_FLAG (s390_readinfo_sccb[91])
|
|
||||||
|
|
||||||
enum ipl_type {
|
enum ipl_type {
|
||||||
IPL_TYPE_NONE = 1,
|
IPL_TYPE_NONE = 1,
|
||||||
IPL_TYPE_UNKNOWN = 2,
|
IPL_TYPE_UNKNOWN = 2,
|
||||||
IPL_TYPE_CCW = 4,
|
IPL_TYPE_CCW = 4,
|
||||||
IPL_TYPE_FCP = 8,
|
IPL_TYPE_FCP = 8,
|
||||||
|
IPL_TYPE_NSS = 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IPL_NONE_STR "none"
|
#define IPL_NONE_STR "none"
|
||||||
#define IPL_UNKNOWN_STR "unknown"
|
#define IPL_UNKNOWN_STR "unknown"
|
||||||
#define IPL_CCW_STR "ccw"
|
#define IPL_CCW_STR "ccw"
|
||||||
#define IPL_FCP_STR "fcp"
|
#define IPL_FCP_STR "fcp"
|
||||||
|
#define IPL_NSS_STR "nss"
|
||||||
|
|
||||||
static char *ipl_type_str(enum ipl_type type)
|
static char *ipl_type_str(enum ipl_type type)
|
||||||
{
|
{
|
||||||
|
@ -50,6 +51,8 @@ static char *ipl_type_str(enum ipl_type type)
|
||||||
return IPL_CCW_STR;
|
return IPL_CCW_STR;
|
||||||
case IPL_TYPE_FCP:
|
case IPL_TYPE_FCP:
|
||||||
return IPL_FCP_STR;
|
return IPL_FCP_STR;
|
||||||
|
case IPL_TYPE_NSS:
|
||||||
|
return IPL_NSS_STR;
|
||||||
case IPL_TYPE_UNKNOWN:
|
case IPL_TYPE_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
return IPL_UNKNOWN_STR;
|
return IPL_UNKNOWN_STR;
|
||||||
|
@ -64,6 +67,7 @@ enum ipl_method {
|
||||||
IPL_METHOD_FCP_RO_DIAG,
|
IPL_METHOD_FCP_RO_DIAG,
|
||||||
IPL_METHOD_FCP_RW_DIAG,
|
IPL_METHOD_FCP_RW_DIAG,
|
||||||
IPL_METHOD_FCP_RO_VM,
|
IPL_METHOD_FCP_RO_VM,
|
||||||
|
IPL_METHOD_NSS,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum shutdown_action {
|
enum shutdown_action {
|
||||||
|
@ -114,11 +118,14 @@ enum diag308_rc {
|
||||||
static int diag308_set_works = 0;
|
static int diag308_set_works = 0;
|
||||||
|
|
||||||
static int reipl_capabilities = IPL_TYPE_UNKNOWN;
|
static int reipl_capabilities = IPL_TYPE_UNKNOWN;
|
||||||
|
|
||||||
static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
|
static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
|
||||||
static enum ipl_method reipl_method = IPL_METHOD_NONE;
|
static enum ipl_method reipl_method = IPL_METHOD_NONE;
|
||||||
static struct ipl_parameter_block *reipl_block_fcp;
|
static struct ipl_parameter_block *reipl_block_fcp;
|
||||||
static struct ipl_parameter_block *reipl_block_ccw;
|
static struct ipl_parameter_block *reipl_block_ccw;
|
||||||
|
|
||||||
|
static char reipl_nss_name[NSS_NAME_SIZE + 1];
|
||||||
|
|
||||||
static int dump_capabilities = IPL_TYPE_NONE;
|
static int dump_capabilities = IPL_TYPE_NONE;
|
||||||
static enum ipl_type dump_type = IPL_TYPE_NONE;
|
static enum ipl_type dump_type = IPL_TYPE_NONE;
|
||||||
static enum ipl_method dump_method = IPL_METHOD_NONE;
|
static enum ipl_method dump_method = IPL_METHOD_NONE;
|
||||||
|
@ -173,6 +180,24 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
|
||||||
sys_##_prefix##_##_name##_show, \
|
sys_##_prefix##_##_name##_show, \
|
||||||
sys_##_prefix##_##_name##_store);
|
sys_##_prefix##_##_name##_store);
|
||||||
|
|
||||||
|
#define DEFINE_IPL_ATTR_STR_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, _value); \
|
||||||
|
} \
|
||||||
|
static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
|
||||||
|
const char *buf, size_t len) \
|
||||||
|
{ \
|
||||||
|
if (sscanf(buf, _fmt_in, _value) != 1) \
|
||||||
|
return -EINVAL; \
|
||||||
|
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)
|
static void make_attrs_ro(struct attribute **attrs)
|
||||||
{
|
{
|
||||||
while (*attrs) {
|
while (*attrs) {
|
||||||
|
@ -189,6 +214,8 @@ static enum ipl_type ipl_get_type(void)
|
||||||
{
|
{
|
||||||
struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
|
struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
|
||||||
|
|
||||||
|
if (ipl_flags & IPL_NSS_VALID)
|
||||||
|
return IPL_TYPE_NSS;
|
||||||
if (!(ipl_flags & IPL_DEVNO_VALID))
|
if (!(ipl_flags & IPL_DEVNO_VALID))
|
||||||
return IPL_TYPE_UNKNOWN;
|
return IPL_TYPE_UNKNOWN;
|
||||||
if (!(ipl_flags & IPL_PARMBLOCK_VALID))
|
if (!(ipl_flags & IPL_PARMBLOCK_VALID))
|
||||||
|
@ -324,6 +351,20 @@ static struct attribute_group ipl_ccw_attr_group = {
|
||||||
.attrs = ipl_ccw_attrs,
|
.attrs = ipl_ccw_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* NSS ipl device attributes */
|
||||||
|
|
||||||
|
DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
|
||||||
|
|
||||||
|
static struct attribute *ipl_nss_attrs[] = {
|
||||||
|
&sys_ipl_type_attr.attr,
|
||||||
|
&sys_ipl_nss_name_attr.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group ipl_nss_attr_group = {
|
||||||
|
.attrs = ipl_nss_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
/* UNKNOWN ipl device attributes */
|
/* UNKNOWN ipl device attributes */
|
||||||
|
|
||||||
static struct attribute *ipl_unknown_attrs[] = {
|
static struct attribute *ipl_unknown_attrs[] = {
|
||||||
|
@ -432,6 +473,21 @@ static struct attribute_group reipl_ccw_attr_group = {
|
||||||
.attrs = reipl_ccw_attrs,
|
.attrs = reipl_ccw_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* NSS reipl device attributes */
|
||||||
|
|
||||||
|
DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
|
||||||
|
|
||||||
|
static struct attribute *reipl_nss_attrs[] = {
|
||||||
|
&sys_reipl_nss_name_attr.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group reipl_nss_attr_group = {
|
||||||
|
.name = IPL_NSS_STR,
|
||||||
|
.attrs = reipl_nss_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
/* reipl type */
|
/* reipl type */
|
||||||
|
|
||||||
static int reipl_set_type(enum ipl_type type)
|
static int reipl_set_type(enum ipl_type type)
|
||||||
|
@ -454,6 +510,9 @@ static int reipl_set_type(enum ipl_type type)
|
||||||
else
|
else
|
||||||
reipl_method = IPL_METHOD_FCP_RO_DIAG;
|
reipl_method = IPL_METHOD_FCP_RO_DIAG;
|
||||||
break;
|
break;
|
||||||
|
case IPL_TYPE_NSS:
|
||||||
|
reipl_method = IPL_METHOD_NSS;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
reipl_method = IPL_METHOD_NONE;
|
reipl_method = IPL_METHOD_NONE;
|
||||||
}
|
}
|
||||||
|
@ -475,6 +534,8 @@ static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
|
||||||
rc = reipl_set_type(IPL_TYPE_CCW);
|
rc = reipl_set_type(IPL_TYPE_CCW);
|
||||||
else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
|
else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
|
||||||
rc = reipl_set_type(IPL_TYPE_FCP);
|
rc = reipl_set_type(IPL_TYPE_FCP);
|
||||||
|
else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
|
||||||
|
rc = reipl_set_type(IPL_TYPE_NSS);
|
||||||
return (rc != 0) ? rc : len;
|
return (rc != 0) ? rc : len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,6 +708,10 @@ void do_reipl(void)
|
||||||
case IPL_METHOD_FCP_RO_VM:
|
case IPL_METHOD_FCP_RO_VM:
|
||||||
__cpcmd("IPL", NULL, 0, NULL);
|
__cpcmd("IPL", NULL, 0, NULL);
|
||||||
break;
|
break;
|
||||||
|
case IPL_METHOD_NSS:
|
||||||
|
sprintf(buf, "IPL %s", reipl_nss_name);
|
||||||
|
__cpcmd(buf, NULL, 0, NULL);
|
||||||
|
break;
|
||||||
case IPL_METHOD_NONE:
|
case IPL_METHOD_NONE:
|
||||||
default:
|
default:
|
||||||
if (MACHINE_IS_VM)
|
if (MACHINE_IS_VM)
|
||||||
|
@ -733,6 +798,10 @@ static int __init ipl_init(void)
|
||||||
case IPL_TYPE_FCP:
|
case IPL_TYPE_FCP:
|
||||||
rc = ipl_register_fcp_files();
|
rc = ipl_register_fcp_files();
|
||||||
break;
|
break;
|
||||||
|
case IPL_TYPE_NSS:
|
||||||
|
rc = sysfs_create_group(&ipl_subsys.kset.kobj,
|
||||||
|
&ipl_nss_attr_group);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
rc = sysfs_create_group(&ipl_subsys.kset.kobj,
|
rc = sysfs_create_group(&ipl_subsys.kset.kobj,
|
||||||
&ipl_unknown_attr_group);
|
&ipl_unknown_attr_group);
|
||||||
|
@ -755,6 +824,20 @@ static void __init reipl_probe(void)
|
||||||
free_page((unsigned long)buffer);
|
free_page((unsigned long)buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __init reipl_nss_init(void)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!MACHINE_IS_VM)
|
||||||
|
return 0;
|
||||||
|
rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
|
||||||
|
reipl_capabilities |= IPL_TYPE_NSS;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init reipl_ccw_init(void)
|
static int __init reipl_ccw_init(void)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -835,6 +918,9 @@ static int __init reipl_init(void)
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
rc = reipl_fcp_init();
|
rc = reipl_fcp_init();
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
rc = reipl_nss_init();
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
rc = reipl_set_type(ipl_get_type());
|
rc = reipl_set_type(ipl_get_type());
|
||||||
|
@ -993,8 +1079,6 @@ static void do_reset_calls(void)
|
||||||
reset->fn();
|
reset->fn();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void reset_mcck_handler(void);
|
|
||||||
extern void reset_pgm_handler(void);
|
|
||||||
extern __u32 dump_prefix_page;
|
extern __u32 dump_prefix_page;
|
||||||
|
|
||||||
void s390_reset_system(void)
|
void s390_reset_system(void)
|
||||||
|
@ -1016,14 +1100,14 @@ void s390_reset_system(void)
|
||||||
__ctl_clear_bit(0,28);
|
__ctl_clear_bit(0,28);
|
||||||
|
|
||||||
/* Set new machine check handler */
|
/* Set new machine check handler */
|
||||||
S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
|
S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
|
||||||
S390_lowcore.mcck_new_psw.addr =
|
S390_lowcore.mcck_new_psw.addr =
|
||||||
PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
|
PSW_ADDR_AMODE | (unsigned long) s390_base_mcck_handler;
|
||||||
|
|
||||||
/* Set new program check handler */
|
/* Set new program check handler */
|
||||||
S390_lowcore.program_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
|
S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
|
||||||
S390_lowcore.program_new_psw.addr =
|
S390_lowcore.program_new_psw.addr =
|
||||||
PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler;
|
PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
|
||||||
|
|
||||||
do_reset_calls();
|
do_reset_calls();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* arch/s390/kernel/irq.c
|
* arch/s390/kernel/irq.c
|
||||||
*
|
*
|
||||||
* S390 version
|
* Copyright IBM Corp. 2004,2007
|
||||||
* Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
|
||||||
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
|
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
|
||||||
|
* Thomas Spatzier (tspat@de.ibm.com)
|
||||||
*
|
*
|
||||||
* This file contains interrupt related functions.
|
* This file contains interrupt related functions.
|
||||||
*/
|
*/
|
||||||
|
@ -14,6 +14,8 @@
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
|
#include <linux/proc_fs.h>
|
||||||
|
#include <linux/profile.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* show_interrupts is needed by /proc/interrupts.
|
* show_interrupts is needed by /proc/interrupts.
|
||||||
|
@ -93,5 +95,12 @@ asmlinkage void do_softirq(void)
|
||||||
|
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(do_softirq);
|
EXPORT_SYMBOL(do_softirq);
|
||||||
|
|
||||||
|
void init_irq_proc(void)
|
||||||
|
{
|
||||||
|
struct proc_dir_entry *root_irq_dir;
|
||||||
|
|
||||||
|
root_irq_dir = proc_mkdir("irq", NULL);
|
||||||
|
create_prof_cpu_mask(root_irq_dir);
|
||||||
|
}
|
||||||
|
|
|
@ -155,15 +155,34 @@ void __kprobes get_instruction_type(struct arch_specific_insn *ainsn)
|
||||||
static int __kprobes swap_instruction(void *aref)
|
static int __kprobes swap_instruction(void *aref)
|
||||||
{
|
{
|
||||||
struct ins_replace_args *args = aref;
|
struct ins_replace_args *args = aref;
|
||||||
|
u32 *addr;
|
||||||
|
u32 instr;
|
||||||
int err = -EFAULT;
|
int err = -EFAULT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Text segment is read-only, hence we use stura to bypass dynamic
|
||||||
|
* address translation to exchange the instruction. Since stura
|
||||||
|
* always operates on four bytes, but we only want to exchange two
|
||||||
|
* bytes do some calculations to get things right. In addition we
|
||||||
|
* shall not cross any page boundaries (vmalloc area!) when writing
|
||||||
|
* the new instruction.
|
||||||
|
*/
|
||||||
|
addr = (u32 *)ALIGN((unsigned long)args->ptr, 4);
|
||||||
|
if ((unsigned long)args->ptr & 2)
|
||||||
|
instr = ((*addr) & 0xffff0000) | args->new;
|
||||||
|
else
|
||||||
|
instr = ((*addr) & 0x0000ffff) | args->new << 16;
|
||||||
|
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"0: mvc 0(2,%2),0(%3)\n"
|
" lra %1,0(%1)\n"
|
||||||
"1: la %0,0\n"
|
"0: stura %2,%1\n"
|
||||||
|
"1: la %0,0\n"
|
||||||
"2:\n"
|
"2:\n"
|
||||||
EX_TABLE(0b,2b)
|
EX_TABLE(0b,2b)
|
||||||
: "+d" (err), "=m" (*args->ptr)
|
: "+d" (err)
|
||||||
: "a" (args->ptr), "a" (&args->new), "m" (args->new));
|
: "a" (addr), "d" (instr)
|
||||||
|
: "memory", "cc");
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +375,7 @@ no_kprobe:
|
||||||
* - When the probed function returns, this probe
|
* - When the probed function returns, this probe
|
||||||
* causes the handlers to fire
|
* causes the handlers to fire
|
||||||
*/
|
*/
|
||||||
void __kprobes kretprobe_trampoline_holder(void)
|
void kretprobe_trampoline_holder(void)
|
||||||
{
|
{
|
||||||
asm volatile(".global kretprobe_trampoline\n"
|
asm volatile(".global kretprobe_trampoline\n"
|
||||||
"kretprobe_trampoline: bcr 0,0\n");
|
"kretprobe_trampoline: bcr 0,0\n");
|
||||||
|
@ -365,7 +384,8 @@ void __kprobes kretprobe_trampoline_holder(void)
|
||||||
/*
|
/*
|
||||||
* Called when the probe at kretprobe trampoline is hit
|
* Called when the probe at kretprobe trampoline is hit
|
||||||
*/
|
*/
|
||||||
int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
|
static int __kprobes trampoline_probe_handler(struct kprobe *p,
|
||||||
|
struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct kretprobe_instance *ri = NULL;
|
struct kretprobe_instance *ri = NULL;
|
||||||
struct hlist_head *head, empty_rp;
|
struct hlist_head *head, empty_rp;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/kexec.h>
|
#include <linux/kexec.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/reboot.h>
|
||||||
#include <asm/cio.h>
|
#include <asm/cio.h>
|
||||||
#include <asm/setup.h>
|
#include <asm/setup.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/moduleloader.h>
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#define DEBUGP printk
|
#define DEBUGP printk
|
||||||
|
@ -58,7 +59,7 @@ void module_free(struct module *mod, void *module_region)
|
||||||
table entries. */
|
table entries. */
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static void
|
||||||
check_rela(Elf_Rela *rela, struct module *me)
|
check_rela(Elf_Rela *rela, struct module *me)
|
||||||
{
|
{
|
||||||
struct mod_arch_syminfo *info;
|
struct mod_arch_syminfo *info;
|
||||||
|
@ -181,7 +182,7 @@ apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
||||||
return -ENOEXEC;
|
return -ENOEXEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static int
|
||||||
apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
|
apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
|
||||||
struct module *me)
|
struct module *me)
|
||||||
{
|
{
|
||||||
|
|
|
@ -144,7 +144,7 @@ static void default_idle(void)
|
||||||
|
|
||||||
trace_hardirqs_on();
|
trace_hardirqs_on();
|
||||||
/* Wait for external, I/O or machine check interrupt. */
|
/* Wait for external, I/O or machine check interrupt. */
|
||||||
__load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT |
|
__load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT |
|
||||||
PSW_MASK_IO | PSW_MASK_EXT);
|
PSW_MASK_IO | PSW_MASK_EXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
|
||||||
struct pt_regs regs;
|
struct pt_regs regs;
|
||||||
|
|
||||||
memset(®s, 0, sizeof(regs));
|
memset(®s, 0, sizeof(regs));
|
||||||
regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
|
regs.psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
|
||||||
regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
|
regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
|
||||||
regs.gprs[9] = (unsigned long) fn;
|
regs.gprs[9] = (unsigned long) fn;
|
||||||
regs.gprs[10] = (unsigned long) arg;
|
regs.gprs[10] = (unsigned long) arg;
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
/*
|
|
||||||
* arch/s390/kernel/profile.c
|
|
||||||
*
|
|
||||||
* Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
|
|
||||||
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#include <linux/proc_fs.h>
|
|
||||||
#include <linux/profile.h>
|
|
||||||
|
|
||||||
static struct proc_dir_entry * root_irq_dir;
|
|
||||||
|
|
||||||
void init_irq_proc(void)
|
|
||||||
{
|
|
||||||
/* create /proc/irq */
|
|
||||||
root_irq_dir = proc_mkdir("irq", NULL);
|
|
||||||
|
|
||||||
/* create /proc/irq/prof_cpu_mask */
|
|
||||||
create_prof_cpu_mask(root_irq_dir);
|
|
||||||
}
|
|
|
@ -86,15 +86,13 @@ FixPerRegisters(struct task_struct *task)
|
||||||
per_info->control_regs.bits.storage_alt_space_ctl = 0;
|
per_info->control_regs.bits.storage_alt_space_ctl = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void set_single_step(struct task_struct *task)
|
||||||
set_single_step(struct task_struct *task)
|
|
||||||
{
|
{
|
||||||
task->thread.per_info.single_step = 1;
|
task->thread.per_info.single_step = 1;
|
||||||
FixPerRegisters(task);
|
FixPerRegisters(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void clear_single_step(struct task_struct *task)
|
||||||
clear_single_step(struct task_struct *task)
|
|
||||||
{
|
{
|
||||||
task->thread.per_info.single_step = 0;
|
task->thread.per_info.single_step = 0;
|
||||||
FixPerRegisters(task);
|
FixPerRegisters(task);
|
||||||
|
@ -232,9 +230,9 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
|
||||||
*/
|
*/
|
||||||
if (addr == (addr_t) &dummy->regs.psw.mask &&
|
if (addr == (addr_t) &dummy->regs.psw.mask &&
|
||||||
#ifdef CONFIG_COMPAT
|
#ifdef CONFIG_COMPAT
|
||||||
data != PSW_MASK_MERGE(PSW_USER32_BITS, data) &&
|
data != PSW_MASK_MERGE(psw_user32_bits, data) &&
|
||||||
#endif
|
#endif
|
||||||
data != PSW_MASK_MERGE(PSW_USER_BITS, data))
|
data != PSW_MASK_MERGE(psw_user_bits, data))
|
||||||
/* Invalid psw mask. */
|
/* Invalid psw mask. */
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
#ifndef CONFIG_64BIT
|
#ifndef CONFIG_64BIT
|
||||||
|
@ -309,7 +307,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
|
||||||
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
|
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
|
||||||
if (copied != sizeof(tmp))
|
if (copied != sizeof(tmp))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
return put_user(tmp, (unsigned long __user *) data);
|
return put_user(tmp, (unsigned long __force __user *) data);
|
||||||
|
|
||||||
case PTRACE_PEEKUSR:
|
case PTRACE_PEEKUSR:
|
||||||
/* read the word at location addr in the USER area. */
|
/* read the word at location addr in the USER area. */
|
||||||
|
@ -331,7 +329,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
|
||||||
|
|
||||||
case PTRACE_PEEKUSR_AREA:
|
case PTRACE_PEEKUSR_AREA:
|
||||||
case PTRACE_POKEUSR_AREA:
|
case PTRACE_POKEUSR_AREA:
|
||||||
if (copy_from_user(&parea, (void __user *) addr,
|
if (copy_from_user(&parea, (void __force __user *) addr,
|
||||||
sizeof(parea)))
|
sizeof(parea)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
addr = parea.kernel_addr;
|
addr = parea.kernel_addr;
|
||||||
|
@ -341,10 +339,11 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
|
||||||
if (request == PTRACE_PEEKUSR_AREA)
|
if (request == PTRACE_PEEKUSR_AREA)
|
||||||
ret = peek_user(child, addr, data);
|
ret = peek_user(child, addr, data);
|
||||||
else {
|
else {
|
||||||
addr_t tmp;
|
addr_t utmp;
|
||||||
if (get_user (tmp, (addr_t __user *) data))
|
if (get_user(utmp,
|
||||||
|
(addr_t __force __user *) data))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
ret = poke_user(child, addr, tmp);
|
ret = poke_user(child, addr, utmp);
|
||||||
}
|
}
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -394,7 +393,7 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
|
||||||
if (addr == (addr_t) &dummy32->regs.psw.mask) {
|
if (addr == (addr_t) &dummy32->regs.psw.mask) {
|
||||||
/* Fake a 31 bit psw mask. */
|
/* Fake a 31 bit psw mask. */
|
||||||
tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32);
|
tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32);
|
||||||
tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp);
|
tmp = PSW32_MASK_MERGE(psw32_user_bits, tmp);
|
||||||
} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
|
} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
|
||||||
/* Fake a 31 bit psw address. */
|
/* Fake a 31 bit psw address. */
|
||||||
tmp = (__u32) task_pt_regs(child)->psw.addr |
|
tmp = (__u32) task_pt_regs(child)->psw.addr |
|
||||||
|
@ -469,11 +468,11 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
|
||||||
*/
|
*/
|
||||||
if (addr == (addr_t) &dummy32->regs.psw.mask) {
|
if (addr == (addr_t) &dummy32->regs.psw.mask) {
|
||||||
/* Build a 64 bit psw mask from 31 bit mask. */
|
/* Build a 64 bit psw mask from 31 bit mask. */
|
||||||
if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp))
|
if (tmp != PSW32_MASK_MERGE(psw32_user_bits, tmp))
|
||||||
/* Invalid psw mask. */
|
/* Invalid psw mask. */
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
task_pt_regs(child)->psw.mask =
|
task_pt_regs(child)->psw.mask =
|
||||||
PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32);
|
PSW_MASK_MERGE(psw_user32_bits, (__u64) tmp << 32);
|
||||||
} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
|
} else if (addr == (addr_t) &dummy32->regs.psw.addr) {
|
||||||
/* Build a 64 bit psw address from 31 bit address. */
|
/* Build a 64 bit psw address from 31 bit address. */
|
||||||
task_pt_regs(child)->psw.addr =
|
task_pt_regs(child)->psw.addr =
|
||||||
|
@ -550,7 +549,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
|
||||||
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
|
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
|
||||||
if (copied != sizeof(tmp))
|
if (copied != sizeof(tmp))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
return put_user(tmp, (unsigned int __user *) data);
|
return put_user(tmp, (unsigned int __force __user *) data);
|
||||||
|
|
||||||
case PTRACE_PEEKUSR:
|
case PTRACE_PEEKUSR:
|
||||||
/* read the word at location addr in the USER area. */
|
/* read the word at location addr in the USER area. */
|
||||||
|
@ -571,7 +570,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
|
||||||
|
|
||||||
case PTRACE_PEEKUSR_AREA:
|
case PTRACE_PEEKUSR_AREA:
|
||||||
case PTRACE_POKEUSR_AREA:
|
case PTRACE_POKEUSR_AREA:
|
||||||
if (copy_from_user(&parea, (void __user *) addr,
|
if (copy_from_user(&parea, (void __force __user *) addr,
|
||||||
sizeof(parea)))
|
sizeof(parea)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
addr = parea.kernel_addr;
|
addr = parea.kernel_addr;
|
||||||
|
@ -581,10 +580,11 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
|
||||||
if (request == PTRACE_PEEKUSR_AREA)
|
if (request == PTRACE_PEEKUSR_AREA)
|
||||||
ret = peek_user_emu31(child, addr, data);
|
ret = peek_user_emu31(child, addr, data);
|
||||||
else {
|
else {
|
||||||
__u32 tmp;
|
__u32 utmp;
|
||||||
if (get_user (tmp, (__u32 __user *) data))
|
if (get_user(utmp,
|
||||||
|
(__u32 __force __user *) data))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
ret = poke_user_emu31(child, addr, tmp);
|
ret = poke_user_emu31(child, addr, utmp);
|
||||||
}
|
}
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -595,17 +595,19 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
|
||||||
return 0;
|
return 0;
|
||||||
case PTRACE_GETEVENTMSG:
|
case PTRACE_GETEVENTMSG:
|
||||||
return put_user((__u32) child->ptrace_message,
|
return put_user((__u32) child->ptrace_message,
|
||||||
(unsigned int __user *) data);
|
(unsigned int __force __user *) data);
|
||||||
case PTRACE_GETSIGINFO:
|
case PTRACE_GETSIGINFO:
|
||||||
if (child->last_siginfo == NULL)
|
if (child->last_siginfo == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return copy_siginfo_to_user32((compat_siginfo_t __user *) data,
|
return copy_siginfo_to_user32((compat_siginfo_t
|
||||||
|
__force __user *) data,
|
||||||
child->last_siginfo);
|
child->last_siginfo);
|
||||||
case PTRACE_SETSIGINFO:
|
case PTRACE_SETSIGINFO:
|
||||||
if (child->last_siginfo == NULL)
|
if (child->last_siginfo == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return copy_siginfo_from_user32(child->last_siginfo,
|
return copy_siginfo_from_user32(child->last_siginfo,
|
||||||
(compat_siginfo_t __user *) data);
|
(compat_siginfo_t
|
||||||
|
__force __user *) data);
|
||||||
}
|
}
|
||||||
return ptrace_request(child, request, addr, data);
|
return ptrace_request(child, request, addr, data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
/*
|
|
||||||
* arch/s390/kernel/reset.S
|
|
||||||
*
|
|
||||||
* Copyright (C) IBM Corp. 2006
|
|
||||||
* Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
|
|
||||||
* Michael Holzheu <holzheu@de.ibm.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <asm/ptrace.h>
|
|
||||||
#include <asm/lowcore.h>
|
|
||||||
|
|
||||||
#ifdef CONFIG_64BIT
|
|
||||||
|
|
||||||
.globl reset_mcck_handler
|
|
||||||
reset_mcck_handler:
|
|
||||||
basr %r13,0
|
|
||||||
0: lg %r15,__LC_PANIC_STACK # load panic stack
|
|
||||||
aghi %r15,-STACK_FRAME_OVERHEAD
|
|
||||||
lg %r1,s390_reset_mcck_handler-0b(%r13)
|
|
||||||
ltgr %r1,%r1
|
|
||||||
jz 1f
|
|
||||||
basr %r14,%r1
|
|
||||||
1: la %r1,4095
|
|
||||||
lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
|
|
||||||
lpswe __LC_MCK_OLD_PSW
|
|
||||||
|
|
||||||
.globl s390_reset_mcck_handler
|
|
||||||
s390_reset_mcck_handler:
|
|
||||||
.quad 0
|
|
||||||
|
|
||||||
.globl reset_pgm_handler
|
|
||||||
reset_pgm_handler:
|
|
||||||
stmg %r0,%r15,__LC_SAVE_AREA
|
|
||||||
basr %r13,0
|
|
||||||
0: lg %r15,__LC_PANIC_STACK # load panic stack
|
|
||||||
aghi %r15,-STACK_FRAME_OVERHEAD
|
|
||||||
lg %r1,s390_reset_pgm_handler-0b(%r13)
|
|
||||||
ltgr %r1,%r1
|
|
||||||
jz 1f
|
|
||||||
basr %r14,%r1
|
|
||||||
lmg %r0,%r15,__LC_SAVE_AREA
|
|
||||||
lpswe __LC_PGM_OLD_PSW
|
|
||||||
1: lpswe disabled_wait_psw-0b(%r13)
|
|
||||||
.globl s390_reset_pgm_handler
|
|
||||||
s390_reset_pgm_handler:
|
|
||||||
.quad 0
|
|
||||||
.align 8
|
|
||||||
disabled_wait_psw:
|
|
||||||
.quad 0x0002000180000000,0x0000000000000000 + reset_pgm_handler
|
|
||||||
|
|
||||||
#else /* CONFIG_64BIT */
|
|
||||||
|
|
||||||
.globl reset_mcck_handler
|
|
||||||
reset_mcck_handler:
|
|
||||||
basr %r13,0
|
|
||||||
0: l %r15,__LC_PANIC_STACK # load panic stack
|
|
||||||
ahi %r15,-STACK_FRAME_OVERHEAD
|
|
||||||
l %r1,s390_reset_mcck_handler-0b(%r13)
|
|
||||||
ltr %r1,%r1
|
|
||||||
jz 1f
|
|
||||||
basr %r14,%r1
|
|
||||||
1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA
|
|
||||||
lpsw __LC_MCK_OLD_PSW
|
|
||||||
|
|
||||||
.globl s390_reset_mcck_handler
|
|
||||||
s390_reset_mcck_handler:
|
|
||||||
.long 0
|
|
||||||
|
|
||||||
.globl reset_pgm_handler
|
|
||||||
reset_pgm_handler:
|
|
||||||
stm %r0,%r15,__LC_SAVE_AREA
|
|
||||||
basr %r13,0
|
|
||||||
0: l %r15,__LC_PANIC_STACK # load panic stack
|
|
||||||
ahi %r15,-STACK_FRAME_OVERHEAD
|
|
||||||
l %r1,s390_reset_pgm_handler-0b(%r13)
|
|
||||||
ltr %r1,%r1
|
|
||||||
jz 1f
|
|
||||||
basr %r14,%r1
|
|
||||||
lm %r0,%r15,__LC_SAVE_AREA
|
|
||||||
lpsw __LC_PGM_OLD_PSW
|
|
||||||
|
|
||||||
1: lpsw disabled_wait_psw-0b(%r13)
|
|
||||||
.globl s390_reset_pgm_handler
|
|
||||||
s390_reset_pgm_handler:
|
|
||||||
.long 0
|
|
||||||
disabled_wait_psw:
|
|
||||||
.align 8
|
|
||||||
.long 0x000a0000,0x00000000 + reset_pgm_handler
|
|
||||||
|
|
||||||
#endif /* CONFIG_64BIT */
|
|
|
@ -125,14 +125,12 @@ void do_extint(struct pt_regs *regs, unsigned short code)
|
||||||
* Make sure that the i/o interrupt did not "overtake"
|
* Make sure that the i/o interrupt did not "overtake"
|
||||||
* the last HZ timer interrupt.
|
* the last HZ timer interrupt.
|
||||||
*/
|
*/
|
||||||
account_ticks();
|
account_ticks(S390_lowcore.int_clock);
|
||||||
kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
|
kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
|
||||||
index = ext_hash(code);
|
index = ext_hash(code);
|
||||||
for (p = ext_int_hash[index]; p; p = p->next) {
|
for (p = ext_int_hash[index]; p; p = p->next) {
|
||||||
if (likely(p->code == code)) {
|
if (likely(p->code == code))
|
||||||
if (likely(p->handler))
|
p->handler(code);
|
||||||
p->handler(code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
irq_exit();
|
irq_exit();
|
||||||
set_irq_regs(old_regs);
|
set_irq_regs(old_regs);
|
||||||
|
|
|
@ -38,6 +38,8 @@
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/notifier.h>
|
#include <linux/notifier.h>
|
||||||
#include <linux/pfn.h>
|
#include <linux/pfn.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
#include <linux/reboot.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
|
@ -49,6 +51,14 @@
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
#include <asm/sections.h>
|
#include <asm/sections.h>
|
||||||
|
#include <asm/ebcdic.h>
|
||||||
|
#include <asm/compat.h>
|
||||||
|
|
||||||
|
long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
|
||||||
|
PSW_MASK_MCHECK | PSW_DEFAULT_KEY);
|
||||||
|
long psw_user_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
|
||||||
|
PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
|
||||||
|
PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* User copy operations.
|
* User copy operations.
|
||||||
|
@ -117,9 +127,9 @@ void __devinit cpu_init (void)
|
||||||
*/
|
*/
|
||||||
char vmhalt_cmd[128] = "";
|
char vmhalt_cmd[128] = "";
|
||||||
char vmpoff_cmd[128] = "";
|
char vmpoff_cmd[128] = "";
|
||||||
char vmpanic_cmd[128] = "";
|
static char vmpanic_cmd[128] = "";
|
||||||
|
|
||||||
static inline void strncpy_skip_quote(char *dst, char *src, int n)
|
static void strncpy_skip_quote(char *dst, char *src, int n)
|
||||||
{
|
{
|
||||||
int sx, dx;
|
int sx, dx;
|
||||||
|
|
||||||
|
@ -275,10 +285,6 @@ static void __init conmode_default(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
extern void machine_restart_smp(char *);
|
|
||||||
extern void machine_halt_smp(void);
|
|
||||||
extern void machine_power_off_smp(void);
|
|
||||||
|
|
||||||
void (*_machine_restart)(char *command) = machine_restart_smp;
|
void (*_machine_restart)(char *command) = machine_restart_smp;
|
||||||
void (*_machine_halt)(void) = machine_halt_smp;
|
void (*_machine_halt)(void) = machine_halt_smp;
|
||||||
void (*_machine_power_off)(void) = machine_power_off_smp;
|
void (*_machine_power_off)(void) = machine_power_off_smp;
|
||||||
|
@ -386,6 +392,84 @@ static int __init early_parse_ipldelay(char *p)
|
||||||
}
|
}
|
||||||
early_param("ipldelay", early_parse_ipldelay);
|
early_param("ipldelay", early_parse_ipldelay);
|
||||||
|
|
||||||
|
#ifdef CONFIG_S390_SWITCH_AMODE
|
||||||
|
unsigned int switch_amode = 0;
|
||||||
|
EXPORT_SYMBOL_GPL(switch_amode);
|
||||||
|
|
||||||
|
static void set_amode_and_uaccess(unsigned long user_amode,
|
||||||
|
unsigned long user32_amode)
|
||||||
|
{
|
||||||
|
psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode |
|
||||||
|
PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
|
||||||
|
PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
psw_user32_bits = PSW_BASE32_BITS | PSW_MASK_DAT | user_amode |
|
||||||
|
PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
|
||||||
|
PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
|
||||||
|
psw32_user_bits = PSW32_BASE_BITS | PSW32_MASK_DAT | user32_amode |
|
||||||
|
PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
|
||||||
|
PSW32_MASK_PSTATE;
|
||||||
|
#endif
|
||||||
|
psw_kernel_bits = PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
|
||||||
|
PSW_MASK_MCHECK | PSW_DEFAULT_KEY;
|
||||||
|
|
||||||
|
if (MACHINE_HAS_MVCOS) {
|
||||||
|
printk("mvcos available.\n");
|
||||||
|
memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess));
|
||||||
|
} else {
|
||||||
|
printk("mvcos not available.\n");
|
||||||
|
memcpy(&uaccess, &uaccess_pt, sizeof(uaccess));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Switch kernel/user addressing modes?
|
||||||
|
*/
|
||||||
|
static int __init early_parse_switch_amode(char *p)
|
||||||
|
{
|
||||||
|
switch_amode = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
early_param("switch_amode", early_parse_switch_amode);
|
||||||
|
|
||||||
|
#else /* CONFIG_S390_SWITCH_AMODE */
|
||||||
|
static inline void set_amode_and_uaccess(unsigned long user_amode,
|
||||||
|
unsigned long user32_amode)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_S390_SWITCH_AMODE */
|
||||||
|
|
||||||
|
#ifdef CONFIG_S390_EXEC_PROTECT
|
||||||
|
unsigned int s390_noexec = 0;
|
||||||
|
EXPORT_SYMBOL_GPL(s390_noexec);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable execute protection?
|
||||||
|
*/
|
||||||
|
static int __init early_parse_noexec(char *p)
|
||||||
|
{
|
||||||
|
if (!strncmp(p, "off", 3))
|
||||||
|
return 0;
|
||||||
|
switch_amode = 1;
|
||||||
|
s390_noexec = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
early_param("noexec", early_parse_noexec);
|
||||||
|
#endif /* CONFIG_S390_EXEC_PROTECT */
|
||||||
|
|
||||||
|
static void setup_addressing_mode(void)
|
||||||
|
{
|
||||||
|
if (s390_noexec) {
|
||||||
|
printk("S390 execute protection active, ");
|
||||||
|
set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (switch_amode) {
|
||||||
|
printk("S390 address spaces switched, ");
|
||||||
|
set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void __init
|
static void __init
|
||||||
setup_lowcore(void)
|
setup_lowcore(void)
|
||||||
{
|
{
|
||||||
|
@ -402,19 +486,21 @@ setup_lowcore(void)
|
||||||
lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
|
lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
|
||||||
lc->restart_psw.addr =
|
lc->restart_psw.addr =
|
||||||
PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
|
PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
|
||||||
lc->external_new_psw.mask = PSW_KERNEL_BITS;
|
if (switch_amode)
|
||||||
|
lc->restart_psw.mask |= PSW_ASC_HOME;
|
||||||
|
lc->external_new_psw.mask = psw_kernel_bits;
|
||||||
lc->external_new_psw.addr =
|
lc->external_new_psw.addr =
|
||||||
PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
|
PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
|
||||||
lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
|
lc->svc_new_psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
|
||||||
lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
|
lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
|
||||||
lc->program_new_psw.mask = PSW_KERNEL_BITS;
|
lc->program_new_psw.mask = psw_kernel_bits;
|
||||||
lc->program_new_psw.addr =
|
lc->program_new_psw.addr =
|
||||||
PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
|
PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
|
||||||
lc->mcck_new_psw.mask =
|
lc->mcck_new_psw.mask =
|
||||||
PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
|
psw_kernel_bits & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
|
||||||
lc->mcck_new_psw.addr =
|
lc->mcck_new_psw.addr =
|
||||||
PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
|
PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
|
||||||
lc->io_new_psw.mask = PSW_KERNEL_BITS;
|
lc->io_new_psw.mask = psw_kernel_bits;
|
||||||
lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
|
lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
|
||||||
lc->ipl_device = S390_lowcore.ipl_device;
|
lc->ipl_device = S390_lowcore.ipl_device;
|
||||||
lc->jiffy_timer = -1LL;
|
lc->jiffy_timer = -1LL;
|
||||||
|
@ -439,7 +525,7 @@ setup_lowcore(void)
|
||||||
static void __init
|
static void __init
|
||||||
setup_resources(void)
|
setup_resources(void)
|
||||||
{
|
{
|
||||||
struct resource *res;
|
struct resource *res, *sub_res;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
code_resource.start = (unsigned long) &_text;
|
code_resource.start = (unsigned long) &_text;
|
||||||
|
@ -464,8 +550,38 @@ setup_resources(void)
|
||||||
res->start = memory_chunk[i].addr;
|
res->start = memory_chunk[i].addr;
|
||||||
res->end = memory_chunk[i].addr + memory_chunk[i].size - 1;
|
res->end = memory_chunk[i].addr + memory_chunk[i].size - 1;
|
||||||
request_resource(&iomem_resource, res);
|
request_resource(&iomem_resource, res);
|
||||||
request_resource(res, &code_resource);
|
|
||||||
request_resource(res, &data_resource);
|
if (code_resource.start >= res->start &&
|
||||||
|
code_resource.start <= res->end &&
|
||||||
|
code_resource.end > res->end) {
|
||||||
|
sub_res = alloc_bootmem_low(sizeof(struct resource));
|
||||||
|
memcpy(sub_res, &code_resource,
|
||||||
|
sizeof(struct resource));
|
||||||
|
sub_res->end = res->end;
|
||||||
|
code_resource.start = res->end + 1;
|
||||||
|
request_resource(res, sub_res);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code_resource.start >= res->start &&
|
||||||
|
code_resource.start <= res->end &&
|
||||||
|
code_resource.end <= res->end)
|
||||||
|
request_resource(res, &code_resource);
|
||||||
|
|
||||||
|
if (data_resource.start >= res->start &&
|
||||||
|
data_resource.start <= res->end &&
|
||||||
|
data_resource.end > res->end) {
|
||||||
|
sub_res = alloc_bootmem_low(sizeof(struct resource));
|
||||||
|
memcpy(sub_res, &data_resource,
|
||||||
|
sizeof(struct resource));
|
||||||
|
sub_res->end = res->end;
|
||||||
|
data_resource.start = res->end + 1;
|
||||||
|
request_resource(res, sub_res);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_resource.start >= res->start &&
|
||||||
|
data_resource.start <= res->end &&
|
||||||
|
data_resource.end <= res->end)
|
||||||
|
request_resource(res, &data_resource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,16 +611,13 @@ static void __init setup_memory_end(void)
|
||||||
}
|
}
|
||||||
if (!memory_end)
|
if (!memory_end)
|
||||||
memory_end = memory_size;
|
memory_end = memory_size;
|
||||||
if (real_size > memory_end)
|
|
||||||
printk("More memory detected than supported. Unused: %luk\n",
|
|
||||||
(real_size - memory_end) >> 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init
|
static void __init
|
||||||
setup_memory(void)
|
setup_memory(void)
|
||||||
{
|
{
|
||||||
unsigned long bootmap_size;
|
unsigned long bootmap_size;
|
||||||
unsigned long start_pfn, end_pfn, init_pfn;
|
unsigned long start_pfn, end_pfn;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -514,10 +627,6 @@ setup_memory(void)
|
||||||
start_pfn = PFN_UP(__pa(&_end));
|
start_pfn = PFN_UP(__pa(&_end));
|
||||||
end_pfn = max_pfn = PFN_DOWN(memory_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
|
#ifdef CONFIG_BLK_DEV_INITRD
|
||||||
/*
|
/*
|
||||||
* Move the initrd in case the bitmap of the bootmem allocater
|
* Move the initrd in case the bitmap of the bootmem allocater
|
||||||
|
@ -651,6 +760,7 @@ setup_arch(char **cmdline_p)
|
||||||
parse_early_param();
|
parse_early_param();
|
||||||
|
|
||||||
setup_memory_end();
|
setup_memory_end();
|
||||||
|
setup_addressing_mode();
|
||||||
setup_memory();
|
setup_memory();
|
||||||
setup_resources();
|
setup_resources();
|
||||||
setup_lowcore();
|
setup_lowcore();
|
||||||
|
@ -694,6 +804,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
|
||||||
struct cpuinfo_S390 *cpuinfo;
|
struct cpuinfo_S390 *cpuinfo;
|
||||||
unsigned long n = (unsigned long) v - 1;
|
unsigned long n = (unsigned long) v - 1;
|
||||||
|
|
||||||
|
s390_adjust_jiffies();
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
if (!n) {
|
if (!n) {
|
||||||
seq_printf(m, "vendor_id : IBM/S390\n"
|
seq_printf(m, "vendor_id : IBM/S390\n"
|
||||||
|
|
|
@ -119,7 +119,7 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
|
||||||
|
|
||||||
/* Copy a 'clean' PSW mask to the user to avoid leaking
|
/* Copy a 'clean' PSW mask to the user to avoid leaking
|
||||||
information about whether PER is currently on. */
|
information about whether PER is currently on. */
|
||||||
user_sregs.regs.psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask);
|
user_sregs.regs.psw.mask = PSW_MASK_MERGE(psw_user_bits, regs->psw.mask);
|
||||||
user_sregs.regs.psw.addr = regs->psw.addr;
|
user_sregs.regs.psw.addr = regs->psw.addr;
|
||||||
memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs));
|
memcpy(&user_sregs.regs.gprs, ®s->gprs, sizeof(sregs->regs.gprs));
|
||||||
memcpy(&user_sregs.regs.acrs, current->thread.acrs,
|
memcpy(&user_sregs.regs.acrs, current->thread.acrs,
|
||||||
|
|
|
@ -22,23 +22,23 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/kernel_stat.h>
|
#include <linux/kernel_stat.h>
|
||||||
#include <linux/smp_lock.h>
|
#include <linux/smp_lock.h>
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/cache.h>
|
#include <linux/cache.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
|
#include <linux/timex.h>
|
||||||
|
#include <asm/setup.h>
|
||||||
#include <asm/sigp.h>
|
#include <asm/sigp.h>
|
||||||
#include <asm/pgalloc.h>
|
#include <asm/pgalloc.h>
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
#include <asm/s390_ext.h>
|
#include <asm/s390_ext.h>
|
||||||
#include <asm/cpcmd.h>
|
#include <asm/cpcmd.h>
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
|
#include <asm/timer.h>
|
||||||
|
|
||||||
extern volatile int __cpu_logical_map[];
|
extern volatile int __cpu_logical_map[];
|
||||||
|
|
||||||
|
@ -53,12 +53,6 @@ cpumask_t cpu_possible_map = CPU_MASK_NONE;
|
||||||
|
|
||||||
static struct task_struct *current_set[NR_CPUS];
|
static struct task_struct *current_set[NR_CPUS];
|
||||||
|
|
||||||
/*
|
|
||||||
* Reboot, halt and power_off routines for SMP.
|
|
||||||
*/
|
|
||||||
extern char vmhalt_cmd[];
|
|
||||||
extern char vmpoff_cmd[];
|
|
||||||
|
|
||||||
static void smp_ext_bitcall(int, ec_bit_sig);
|
static void smp_ext_bitcall(int, ec_bit_sig);
|
||||||
static void smp_ext_bitcall_others(ec_bit_sig);
|
static void smp_ext_bitcall_others(ec_bit_sig);
|
||||||
|
|
||||||
|
@ -200,7 +194,7 @@ int smp_call_function_on(void (*func) (void *info), void *info,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(smp_call_function_on);
|
EXPORT_SYMBOL(smp_call_function_on);
|
||||||
|
|
||||||
static inline void do_send_stop(void)
|
static void do_send_stop(void)
|
||||||
{
|
{
|
||||||
int cpu, rc;
|
int cpu, rc;
|
||||||
|
|
||||||
|
@ -214,7 +208,7 @@ static inline void do_send_stop(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void do_store_status(void)
|
static void do_store_status(void)
|
||||||
{
|
{
|
||||||
int cpu, rc;
|
int cpu, rc;
|
||||||
|
|
||||||
|
@ -230,7 +224,7 @@ static inline void do_store_status(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void do_wait_for_stop(void)
|
static void do_wait_for_stop(void)
|
||||||
{
|
{
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
|
@ -250,7 +244,7 @@ static inline void do_wait_for_stop(void)
|
||||||
void smp_send_stop(void)
|
void smp_send_stop(void)
|
||||||
{
|
{
|
||||||
/* Disable all interrupts/machine checks */
|
/* Disable all interrupts/machine checks */
|
||||||
__load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK);
|
__load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
|
||||||
|
|
||||||
/* write magic number to zero page (absolute 0) */
|
/* write magic number to zero page (absolute 0) */
|
||||||
lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
|
lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
|
||||||
|
@ -298,7 +292,7 @@ void machine_power_off_smp(void)
|
||||||
* cpus are handled.
|
* cpus are handled.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void do_ext_call_interrupt(__u16 code)
|
static void do_ext_call_interrupt(__u16 code)
|
||||||
{
|
{
|
||||||
unsigned long bits;
|
unsigned long bits;
|
||||||
|
|
||||||
|
@ -385,7 +379,7 @@ struct ec_creg_mask_parms {
|
||||||
/*
|
/*
|
||||||
* callback for setting/clearing control bits
|
* callback for setting/clearing control bits
|
||||||
*/
|
*/
|
||||||
void smp_ctl_bit_callback(void *info) {
|
static void smp_ctl_bit_callback(void *info) {
|
||||||
struct ec_creg_mask_parms *pp = info;
|
struct ec_creg_mask_parms *pp = info;
|
||||||
unsigned long cregs[16];
|
unsigned long cregs[16];
|
||||||
int i;
|
int i;
|
||||||
|
@ -458,17 +452,15 @@ __init smp_count_cpus(void)
|
||||||
/*
|
/*
|
||||||
* Activate a secondary processor.
|
* Activate a secondary processor.
|
||||||
*/
|
*/
|
||||||
extern void init_cpu_timer(void);
|
|
||||||
extern void init_cpu_vtimer(void);
|
|
||||||
|
|
||||||
int __devinit start_secondary(void *cpuvoid)
|
int __devinit start_secondary(void *cpuvoid)
|
||||||
{
|
{
|
||||||
/* Setup the cpu */
|
/* Setup the cpu */
|
||||||
cpu_init();
|
cpu_init();
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
/* init per CPU timer */
|
/* Enable TOD clock interrupts on the secondary cpu. */
|
||||||
init_cpu_timer();
|
init_cpu_timer();
|
||||||
#ifdef CONFIG_VIRT_TIMER
|
#ifdef CONFIG_VIRT_TIMER
|
||||||
|
/* Enable cpu timer interrupts on the secondary cpu. */
|
||||||
init_cpu_vtimer();
|
init_cpu_vtimer();
|
||||||
#endif
|
#endif
|
||||||
/* Enable pfault pseudo page faults on this cpu. */
|
/* Enable pfault pseudo page faults on this cpu. */
|
||||||
|
@ -542,7 +534,7 @@ smp_put_cpu(int cpu)
|
||||||
spin_unlock_irqrestore(&smp_reserve_lock, flags);
|
spin_unlock_irqrestore(&smp_reserve_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static int
|
||||||
cpu_stopped(int cpu)
|
cpu_stopped(int cpu)
|
||||||
{
|
{
|
||||||
__u32 status;
|
__u32 status;
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
#include <linux/stacktrace.h>
|
#include <linux/stacktrace.h>
|
||||||
#include <linux/kallsyms.h>
|
#include <linux/kallsyms.h>
|
||||||
|
|
||||||
static inline unsigned long save_context_stack(struct stack_trace *trace,
|
static unsigned long save_context_stack(struct stack_trace *trace,
|
||||||
unsigned int *skip,
|
unsigned int *skip,
|
||||||
unsigned long sp,
|
unsigned long sp,
|
||||||
unsigned long low,
|
unsigned long low,
|
||||||
unsigned long high)
|
unsigned long high)
|
||||||
{
|
{
|
||||||
struct stack_frame *sf;
|
struct stack_frame *sf;
|
||||||
struct pt_regs *regs;
|
struct pt_regs *regs;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -283,7 +283,7 @@ char *task_show_regs(struct task_struct *task, char *buffer)
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_SPINLOCK(die_lock);
|
static DEFINE_SPINLOCK(die_lock);
|
||||||
|
|
||||||
void die(const char * str, struct pt_regs * regs, long err)
|
void die(const char * str, struct pt_regs * regs, long err)
|
||||||
{
|
{
|
||||||
|
@ -364,8 +364,7 @@ void __kprobes do_single_step(struct pt_regs *regs)
|
||||||
force_sig(SIGTRAP, current);
|
force_sig(SIGTRAP, current);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage void
|
static void default_trap_handler(struct pt_regs * regs, long interruption_code)
|
||||||
default_trap_handler(struct pt_regs * regs, long interruption_code)
|
|
||||||
{
|
{
|
||||||
if (regs->psw.mask & PSW_MASK_PSTATE) {
|
if (regs->psw.mask & PSW_MASK_PSTATE) {
|
||||||
local_irq_enable();
|
local_irq_enable();
|
||||||
|
@ -376,7 +375,7 @@ default_trap_handler(struct pt_regs * regs, long interruption_code)
|
||||||
}
|
}
|
||||||
|
|
||||||
#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
|
#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
|
||||||
asmlinkage void name(struct pt_regs * regs, long interruption_code) \
|
static void name(struct pt_regs * regs, long interruption_code) \
|
||||||
{ \
|
{ \
|
||||||
siginfo_t info; \
|
siginfo_t info; \
|
||||||
info.si_signo = signr; \
|
info.si_signo = signr; \
|
||||||
|
@ -442,7 +441,7 @@ do_fp_trap(struct pt_regs *regs, void __user *location,
|
||||||
"floating point exception", regs, &si);
|
"floating point exception", regs, &si);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
|
static void illegal_op(struct pt_regs * regs, long interruption_code)
|
||||||
{
|
{
|
||||||
siginfo_t info;
|
siginfo_t info;
|
||||||
__u8 opcode[6];
|
__u8 opcode[6];
|
||||||
|
@ -491,8 +490,15 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
|
||||||
#endif
|
#endif
|
||||||
} else
|
} else
|
||||||
signal = SIGILL;
|
signal = SIGILL;
|
||||||
} else
|
} else {
|
||||||
signal = SIGILL;
|
/*
|
||||||
|
* If we get an illegal op in kernel mode, send it through the
|
||||||
|
* kprobes notifier. If kprobes doesn't pick it up, SIGILL
|
||||||
|
*/
|
||||||
|
if (notify_die(DIE_BPT, "bpt", regs, interruption_code,
|
||||||
|
3, SIGTRAP) != NOTIFY_STOP)
|
||||||
|
signal = SIGILL;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_MATHEMU
|
#ifdef CONFIG_MATHEMU
|
||||||
if (signal == SIGFPE)
|
if (signal == SIGFPE)
|
||||||
|
@ -585,7 +591,7 @@ DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
|
||||||
ILL_ILLOPN, get_check_address(regs));
|
ILL_ILLOPN, get_check_address(regs));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
|
static void data_exception(struct pt_regs * regs, long interruption_code)
|
||||||
{
|
{
|
||||||
__u16 __user *location;
|
__u16 __user *location;
|
||||||
int signal = 0;
|
int signal = 0;
|
||||||
|
@ -675,7 +681,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code)
|
static void space_switch_exception(struct pt_regs * regs, long int_code)
|
||||||
{
|
{
|
||||||
siginfo_t info;
|
siginfo_t info;
|
||||||
|
|
||||||
|
|
|
@ -31,19 +31,20 @@ SECTIONS
|
||||||
|
|
||||||
_etext = .; /* End of text section */
|
_etext = .; /* End of text section */
|
||||||
|
|
||||||
. = ALIGN(16); /* Exception table */
|
|
||||||
__start___ex_table = .;
|
|
||||||
__ex_table : { *(__ex_table) }
|
|
||||||
__stop___ex_table = .;
|
|
||||||
|
|
||||||
RODATA
|
RODATA
|
||||||
|
|
||||||
#ifdef CONFIG_SHARED_KERNEL
|
#ifdef CONFIG_SHARED_KERNEL
|
||||||
. = ALIGN(1048576); /* VM shared segments are 1MB aligned */
|
. = ALIGN(1048576); /* VM shared segments are 1MB aligned */
|
||||||
|
|
||||||
_eshared = .; /* End of shareable data */
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
. = ALIGN(4096);
|
||||||
|
_eshared = .; /* End of shareable data */
|
||||||
|
|
||||||
|
. = ALIGN(16); /* Exception table */
|
||||||
|
__start___ex_table = .;
|
||||||
|
__ex_table : { *(__ex_table) }
|
||||||
|
__stop___ex_table = .;
|
||||||
|
|
||||||
.data : { /* Data */
|
.data : { /* Data */
|
||||||
*(.data)
|
*(.data)
|
||||||
CONSTRUCTORS
|
CONSTRUCTORS
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include <asm/irq_regs.h>
|
#include <asm/irq_regs.h>
|
||||||
|
|
||||||
static ext_int_info_t ext_int_info_timer;
|
static ext_int_info_t ext_int_info_timer;
|
||||||
DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
|
static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
|
||||||
|
|
||||||
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
|
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
|
||||||
/*
|
/*
|
||||||
|
@ -524,16 +524,15 @@ EXPORT_SYMBOL(del_virt_timer);
|
||||||
void init_cpu_vtimer(void)
|
void init_cpu_vtimer(void)
|
||||||
{
|
{
|
||||||
struct vtimer_queue *vt_list;
|
struct vtimer_queue *vt_list;
|
||||||
unsigned long cr0;
|
|
||||||
|
|
||||||
/* kick the virtual timer */
|
/* kick the virtual timer */
|
||||||
S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
|
S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
|
||||||
S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
|
S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
|
||||||
asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
|
asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
|
||||||
asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
|
asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
|
||||||
__ctl_store(cr0, 0, 0);
|
|
||||||
cr0 |= 0x400;
|
/* enable cpu timer interrupts */
|
||||||
__ctl_load(cr0, 0, 0);
|
__ctl_set_bit(0,10);
|
||||||
|
|
||||||
vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
|
vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
|
||||||
INIT_LIST_HEAD(&vt_list->list);
|
INIT_LIST_HEAD(&vt_list->list);
|
||||||
|
@ -572,6 +571,7 @@ void __init vtime_init(void)
|
||||||
if (register_idle_notifier(&vtimer_idle_nb))
|
if (register_idle_notifier(&vtimer_idle_nb))
|
||||||
panic("Couldn't register idle notifier");
|
panic("Couldn't register idle notifier");
|
||||||
|
|
||||||
|
/* Enable cpu timer interrupts on the boot cpu. */
|
||||||
init_cpu_vtimer();
|
init_cpu_vtimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
EXTRA_AFLAGS := -traditional
|
EXTRA_AFLAGS := -traditional
|
||||||
|
|
||||||
lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
|
lib-y += delay.o string.o uaccess_std.o uaccess_pt.o qrnnd.o
|
||||||
lib-$(CONFIG_32BIT) += div64.o
|
lib-$(CONFIG_32BIT) += div64.o
|
||||||
lib-$(CONFIG_64BIT) += uaccess_mvcos.o
|
lib-$(CONFIG_64BIT) += uaccess_mvcos.o
|
||||||
lib-$(CONFIG_SMP) += spinlock.o
|
lib-$(CONFIG_SMP) += spinlock.o
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* arch/s390/kernel/delay.c
|
* arch/s390/lib/delay.c
|
||||||
* Precise Delay Loops for S390
|
* Precise Delay Loops for S390
|
||||||
*
|
*
|
||||||
* S390 version
|
* S390 version
|
||||||
|
@ -13,10 +13,8 @@
|
||||||
|
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
#include <linux/timex.h>
|
||||||
#ifdef CONFIG_SMP
|
#include <linux/irqflags.h>
|
||||||
#include <asm/smp.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void __delay(unsigned long loops)
|
void __delay(unsigned long loops)
|
||||||
{
|
{
|
||||||
|
@ -31,17 +29,39 @@ void __delay(unsigned long loops)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Waits for 'usecs' microseconds using the tod clock, giving up the time slice
|
* Waits for 'usecs' microseconds using the TOD clock comparator.
|
||||||
* of the virtual PU inbetween to avoid congestion.
|
|
||||||
*/
|
*/
|
||||||
void __udelay(unsigned long usecs)
|
void __udelay(unsigned long usecs)
|
||||||
{
|
{
|
||||||
uint64_t start_cc;
|
u64 end, time, jiffy_timer = 0;
|
||||||
|
unsigned long flags, cr0, mask, dummy;
|
||||||
|
|
||||||
if (usecs == 0)
|
local_irq_save(flags);
|
||||||
return;
|
if (raw_irqs_disabled_flags(flags)) {
|
||||||
start_cc = get_clock();
|
jiffy_timer = S390_lowcore.jiffy_timer;
|
||||||
do {
|
S390_lowcore.jiffy_timer = -1ULL - (4096 << 12);
|
||||||
cpu_relax();
|
__ctl_store(cr0, 0, 0);
|
||||||
} while (((get_clock() - start_cc)/4096) < usecs);
|
dummy = (cr0 & 0xffff00e0) | 0x00000800;
|
||||||
|
__ctl_load(dummy , 0, 0);
|
||||||
|
mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
|
||||||
|
} else
|
||||||
|
mask = psw_kernel_bits | PSW_MASK_WAIT |
|
||||||
|
PSW_MASK_EXT | PSW_MASK_IO;
|
||||||
|
|
||||||
|
end = get_clock() + ((u64) usecs << 12);
|
||||||
|
do {
|
||||||
|
time = end < S390_lowcore.jiffy_timer ?
|
||||||
|
end : S390_lowcore.jiffy_timer;
|
||||||
|
set_clock_comparator(time);
|
||||||
|
trace_hardirqs_on();
|
||||||
|
__load_psw_mask(mask);
|
||||||
|
local_irq_disable();
|
||||||
|
} while (get_clock() < end);
|
||||||
|
|
||||||
|
if (raw_irqs_disabled_flags(flags)) {
|
||||||
|
__ctl_load(cr0, 0, 0);
|
||||||
|
S390_lowcore.jiffy_timer = jiffy_timer;
|
||||||
|
}
|
||||||
|
set_clock_comparator(S390_lowcore.jiffy_timer);
|
||||||
|
local_irq_restore(flags);
|
||||||
}
|
}
|
||||||
|
|
77
arch/s390/lib/qrnnd.S
Normal file
77
arch/s390/lib/qrnnd.S
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
# S/390 __udiv_qrnnd
|
||||||
|
|
||||||
|
# r2 : &__r
|
||||||
|
# r3 : upper half of 64 bit word n
|
||||||
|
# r4 : lower half of 64 bit word n
|
||||||
|
# r5 : divisor d
|
||||||
|
# the reminder r of the division is to be stored to &__r and
|
||||||
|
# the quotient q is to be returned
|
||||||
|
|
||||||
|
.text
|
||||||
|
.globl __udiv_qrnnd
|
||||||
|
__udiv_qrnnd:
|
||||||
|
st %r2,24(%r15) # store pointer to reminder for later
|
||||||
|
lr %r0,%r3 # reload n
|
||||||
|
lr %r1,%r4
|
||||||
|
ltr %r2,%r5 # reload and test divisor
|
||||||
|
jp 5f
|
||||||
|
# divisor >= 0x80000000
|
||||||
|
srdl %r0,2 # n/4
|
||||||
|
srl %r2,1 # d/2
|
||||||
|
slr %r1,%r2 # special case if last bit of d is set
|
||||||
|
brc 3,0f # (n/4) div (n/2) can overflow by 1
|
||||||
|
ahi %r0,-1 # trick: subtract n/2, then divide
|
||||||
|
0: dr %r0,%r2 # signed division
|
||||||
|
ahi %r1,1 # trick part 2: add 1 to the quotient
|
||||||
|
# now (n >> 2) = (d >> 1) * %r1 + %r0
|
||||||
|
lhi %r3,1
|
||||||
|
nr %r3,%r1 # test last bit of q
|
||||||
|
jz 1f
|
||||||
|
alr %r0,%r2 # add (d>>1) to r
|
||||||
|
1: srl %r1,1 # q >>= 1
|
||||||
|
# now (n >> 2) = (d&-2) * %r1 + %r0
|
||||||
|
lhi %r3,1
|
||||||
|
nr %r3,%r5 # test last bit of d
|
||||||
|
jz 2f
|
||||||
|
slr %r0,%r1 # r -= q
|
||||||
|
brc 3,2f # borrow ?
|
||||||
|
alr %r0,%r5 # r += d
|
||||||
|
ahi %r1,-1
|
||||||
|
2: # now (n >> 2) = d * %r1 + %r0
|
||||||
|
alr %r1,%r1 # q <<= 1
|
||||||
|
alr %r0,%r0 # r <<= 1
|
||||||
|
brc 12,3f # overflow on r ?
|
||||||
|
slr %r0,%r5 # r -= d
|
||||||
|
ahi %r1,1 # q += 1
|
||||||
|
3: lhi %r3,2
|
||||||
|
nr %r3,%r4 # test next to last bit of n
|
||||||
|
jz 4f
|
||||||
|
ahi %r0,1 # r += 1
|
||||||
|
4: clr %r0,%r5 # r >= d ?
|
||||||
|
jl 6f
|
||||||
|
slr %r0,%r5 # r -= d
|
||||||
|
ahi %r1,1 # q += 1
|
||||||
|
# now (n >> 1) = d * %r1 + %r0
|
||||||
|
j 6f
|
||||||
|
5: # divisor < 0x80000000
|
||||||
|
srdl %r0,1
|
||||||
|
dr %r0,%r2 # signed division
|
||||||
|
# now (n >> 1) = d * %r1 + %r0
|
||||||
|
6: alr %r1,%r1 # q <<= 1
|
||||||
|
alr %r0,%r0 # r <<= 1
|
||||||
|
brc 12,7f # overflow on r ?
|
||||||
|
slr %r0,%r5 # r -= d
|
||||||
|
ahi %r1,1 # q += 1
|
||||||
|
7: lhi %r3,1
|
||||||
|
nr %r3,%r4 # isolate last bit of n
|
||||||
|
alr %r0,%r3 # r += (n & 1)
|
||||||
|
clr %r0,%r5 # r >= d ?
|
||||||
|
jl 8f
|
||||||
|
slr %r0,%r5 # r -= d
|
||||||
|
ahi %r1,1 # q += 1
|
||||||
|
8: # now n = d * %r1 + %r0
|
||||||
|
l %r2,24(%r15)
|
||||||
|
st %r0,0(%r2)
|
||||||
|
lr %r2,%r1
|
||||||
|
br %r14
|
||||||
|
.end __udiv_qrnnd
|
23
arch/s390/lib/uaccess.h
Normal file
23
arch/s390/lib/uaccess.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* arch/s390/uaccess.h
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2007
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __ARCH_S390_LIB_UACCESS_H
|
||||||
|
#define __ARCH_S390_LIB_UACCESS_H
|
||||||
|
|
||||||
|
extern size_t copy_from_user_std(size_t, const void __user *, void *);
|
||||||
|
extern size_t copy_to_user_std(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_cmpxchg_std(int __user *, int, int);
|
||||||
|
extern int futex_atomic_op_std(int, int __user *, int, int *);
|
||||||
|
|
||||||
|
extern size_t copy_from_user_pt(size_t, const void __user *, void *);
|
||||||
|
extern size_t copy_to_user_pt(size_t, void __user *, const void *);
|
||||||
|
extern int futex_atomic_op_pt(int, int __user *, int, int *);
|
||||||
|
extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
|
||||||
|
|
||||||
|
#endif /* __ARCH_S390_LIB_UACCESS_H */
|
|
@ -12,6 +12,7 @@
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/futex.h>
|
#include <asm/futex.h>
|
||||||
|
#include "uaccess.h"
|
||||||
|
|
||||||
#ifndef __s390x__
|
#ifndef __s390x__
|
||||||
#define AHI "ahi"
|
#define AHI "ahi"
|
||||||
|
@ -27,10 +28,7 @@
|
||||||
#define SLR "slgr"
|
#define SLR "slgr"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern size_t copy_from_user_std(size_t, const void __user *, void *);
|
static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
|
||||||
extern size_t copy_to_user_std(size_t, void __user *, const void *);
|
|
||||||
|
|
||||||
size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
|
|
||||||
{
|
{
|
||||||
register unsigned long reg0 asm("0") = 0x81UL;
|
register unsigned long reg0 asm("0") = 0x81UL;
|
||||||
unsigned long tmp1, tmp2;
|
unsigned long tmp1, tmp2;
|
||||||
|
@ -69,14 +67,14 @@ size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x)
|
static size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x)
|
||||||
{
|
{
|
||||||
if (size <= 256)
|
if (size <= 256)
|
||||||
return copy_from_user_std(size, ptr, x);
|
return copy_from_user_std(size, ptr, x);
|
||||||
return copy_from_user_mvcos(size, ptr, x);
|
return copy_from_user_mvcos(size, ptr, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
|
static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
|
||||||
{
|
{
|
||||||
register unsigned long reg0 asm("0") = 0x810000UL;
|
register unsigned long reg0 asm("0") = 0x810000UL;
|
||||||
unsigned long tmp1, tmp2;
|
unsigned long tmp1, tmp2;
|
||||||
|
@ -105,14 +103,16 @@ size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t copy_to_user_mvcos_check(size_t size, void __user *ptr, const void *x)
|
static size_t copy_to_user_mvcos_check(size_t size, void __user *ptr,
|
||||||
|
const void *x)
|
||||||
{
|
{
|
||||||
if (size <= 256)
|
if (size <= 256)
|
||||||
return copy_to_user_std(size, ptr, x);
|
return copy_to_user_std(size, ptr, x);
|
||||||
return copy_to_user_mvcos(size, ptr, x);
|
return copy_to_user_mvcos(size, ptr, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from)
|
static size_t copy_in_user_mvcos(size_t size, void __user *to,
|
||||||
|
const void __user *from)
|
||||||
{
|
{
|
||||||
register unsigned long reg0 asm("0") = 0x810081UL;
|
register unsigned long reg0 asm("0") = 0x810081UL;
|
||||||
unsigned long tmp1, tmp2;
|
unsigned long tmp1, tmp2;
|
||||||
|
@ -134,7 +134,7 @@ size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t clear_user_mvcos(size_t size, void __user *to)
|
static size_t clear_user_mvcos(size_t size, void __user *to)
|
||||||
{
|
{
|
||||||
register unsigned long reg0 asm("0") = 0x810000UL;
|
register unsigned long reg0 asm("0") = 0x810000UL;
|
||||||
unsigned long tmp1, tmp2;
|
unsigned long tmp1, tmp2;
|
||||||
|
@ -162,10 +162,43 @@ size_t clear_user_mvcos(size_t size, void __user *to)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern size_t strnlen_user_std(size_t, const char __user *);
|
static size_t strnlen_user_mvcos(size_t count, const char __user *src)
|
||||||
extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
|
{
|
||||||
extern int futex_atomic_op(int, int __user *, int, int *);
|
char buf[256];
|
||||||
extern int futex_atomic_cmpxchg(int __user *, int, int);
|
int rc;
|
||||||
|
size_t done, len, len_str;
|
||||||
|
|
||||||
|
done = 0;
|
||||||
|
do {
|
||||||
|
len = min(count - done, (size_t) 256);
|
||||||
|
rc = uaccess.copy_from_user(len, src + done, buf);
|
||||||
|
if (unlikely(rc == len))
|
||||||
|
return 0;
|
||||||
|
len -= rc;
|
||||||
|
len_str = strnlen(buf, len);
|
||||||
|
done += len_str;
|
||||||
|
} while ((len_str == len) && (done < count));
|
||||||
|
return done + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
|
||||||
|
char *dst)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
size_t done, len, len_str;
|
||||||
|
|
||||||
|
done = 0;
|
||||||
|
do {
|
||||||
|
len = min(count - done, (size_t) 4096);
|
||||||
|
rc = uaccess.copy_from_user(len, src + done, dst);
|
||||||
|
if (unlikely(rc == len))
|
||||||
|
return -EFAULT;
|
||||||
|
len -= rc;
|
||||||
|
len_str = strnlen(dst, len);
|
||||||
|
done += len_str;
|
||||||
|
} while ((len_str == len) && (done < count));
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
struct uaccess_ops uaccess_mvcos = {
|
struct uaccess_ops uaccess_mvcos = {
|
||||||
.copy_from_user = copy_from_user_mvcos_check,
|
.copy_from_user = copy_from_user_mvcos_check,
|
||||||
|
@ -176,6 +209,21 @@ struct uaccess_ops uaccess_mvcos = {
|
||||||
.clear_user = clear_user_mvcos,
|
.clear_user = clear_user_mvcos,
|
||||||
.strnlen_user = strnlen_user_std,
|
.strnlen_user = strnlen_user_std,
|
||||||
.strncpy_from_user = strncpy_from_user_std,
|
.strncpy_from_user = strncpy_from_user_std,
|
||||||
.futex_atomic_op = futex_atomic_op,
|
.futex_atomic_op = futex_atomic_op_std,
|
||||||
.futex_atomic_cmpxchg = futex_atomic_cmpxchg,
|
.futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_S390_SWITCH_AMODE
|
||||||
|
struct uaccess_ops uaccess_mvcos_switch = {
|
||||||
|
.copy_from_user = copy_from_user_mvcos,
|
||||||
|
.copy_from_user_small = copy_from_user_mvcos,
|
||||||
|
.copy_to_user = copy_to_user_mvcos,
|
||||||
|
.copy_to_user_small = copy_to_user_mvcos,
|
||||||
|
.copy_in_user = copy_in_user_mvcos,
|
||||||
|
.clear_user = clear_user_mvcos,
|
||||||
|
.strnlen_user = strnlen_user_mvcos,
|
||||||
|
.strncpy_from_user = strncpy_from_user_mvcos,
|
||||||
|
.futex_atomic_op = futex_atomic_op_pt,
|
||||||
|
.futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
/*
|
/*
|
||||||
* arch/s390/lib/uaccess_pt.c
|
* arch/s390/lib/uaccess_pt.c
|
||||||
*
|
*
|
||||||
* User access functions based on page table walks.
|
* User access functions based on page table walks for enhanced
|
||||||
|
* system layout without hardware support.
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2006
|
* Copyright IBM Corp. 2006
|
||||||
* Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com)
|
* Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com)
|
||||||
|
@ -12,9 +13,10 @@
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/futex.h>
|
#include <asm/futex.h>
|
||||||
|
#include "uaccess.h"
|
||||||
|
|
||||||
static inline int __handle_fault(struct mm_struct *mm, unsigned long address,
|
static int __handle_fault(struct mm_struct *mm, unsigned long address,
|
||||||
int write_access)
|
int write_access)
|
||||||
{
|
{
|
||||||
struct vm_area_struct *vma;
|
struct vm_area_struct *vma;
|
||||||
int ret = -EFAULT;
|
int ret = -EFAULT;
|
||||||
|
@ -79,8 +81,8 @@ out_sigbus:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
|
static size_t __user_copy_pt(unsigned long uaddr, void *kptr,
|
||||||
size_t n, int write_user)
|
size_t n, int write_user)
|
||||||
{
|
{
|
||||||
struct mm_struct *mm = current->mm;
|
struct mm_struct *mm = current->mm;
|
||||||
unsigned long offset, pfn, done, size;
|
unsigned long offset, pfn, done, size;
|
||||||
|
@ -133,6 +135,49 @@ fault:
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do DAT for user address by page table walk, return kernel address.
|
||||||
|
* This function needs to be called with current->mm->page_table_lock held.
|
||||||
|
*/
|
||||||
|
static unsigned long __dat_user_addr(unsigned long uaddr)
|
||||||
|
{
|
||||||
|
struct mm_struct *mm = current->mm;
|
||||||
|
unsigned long pfn, ret;
|
||||||
|
pgd_t *pgd;
|
||||||
|
pmd_t *pmd;
|
||||||
|
pte_t *pte;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
retry:
|
||||||
|
pgd = pgd_offset(mm, uaddr);
|
||||||
|
if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
|
||||||
|
goto fault;
|
||||||
|
|
||||||
|
pmd = pmd_offset(pgd, uaddr);
|
||||||
|
if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
|
||||||
|
goto fault;
|
||||||
|
|
||||||
|
pte = pte_offset_map(pmd, uaddr);
|
||||||
|
if (!pte || !pte_present(*pte))
|
||||||
|
goto fault;
|
||||||
|
|
||||||
|
pfn = pte_pfn(*pte);
|
||||||
|
if (!pfn_valid(pfn))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
fault:
|
||||||
|
spin_unlock(&mm->page_table_lock);
|
||||||
|
rc = __handle_fault(mm, uaddr, 0);
|
||||||
|
spin_lock(&mm->page_table_lock);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
|
size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
|
||||||
{
|
{
|
||||||
size_t rc;
|
size_t rc;
|
||||||
|
@ -155,3 +200,277 @@ size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
|
||||||
}
|
}
|
||||||
return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
|
return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t clear_user_pt(size_t n, void __user *to)
|
||||||
|
{
|
||||||
|
long done, size, ret;
|
||||||
|
|
||||||
|
if (segment_eq(get_fs(), KERNEL_DS)) {
|
||||||
|
memset((void __kernel __force *) to, 0, n);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
done = 0;
|
||||||
|
do {
|
||||||
|
if (n - done > PAGE_SIZE)
|
||||||
|
size = PAGE_SIZE;
|
||||||
|
else
|
||||||
|
size = n - done;
|
||||||
|
ret = __user_copy_pt((unsigned long) to + done,
|
||||||
|
&empty_zero_page, size, 1);
|
||||||
|
done += size;
|
||||||
|
if (ret)
|
||||||
|
return ret + n - done;
|
||||||
|
} while (done < n);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t strnlen_user_pt(size_t count, const char __user *src)
|
||||||
|
{
|
||||||
|
char *addr;
|
||||||
|
unsigned long uaddr = (unsigned long) src;
|
||||||
|
struct mm_struct *mm = current->mm;
|
||||||
|
unsigned long offset, pfn, done, len;
|
||||||
|
pgd_t *pgd;
|
||||||
|
pmd_t *pmd;
|
||||||
|
pte_t *pte;
|
||||||
|
size_t len_str;
|
||||||
|
|
||||||
|
if (segment_eq(get_fs(), KERNEL_DS))
|
||||||
|
return strnlen((const char __kernel __force *) src, count) + 1;
|
||||||
|
done = 0;
|
||||||
|
retry:
|
||||||
|
spin_lock(&mm->page_table_lock);
|
||||||
|
do {
|
||||||
|
pgd = pgd_offset(mm, uaddr);
|
||||||
|
if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
|
||||||
|
goto fault;
|
||||||
|
|
||||||
|
pmd = pmd_offset(pgd, uaddr);
|
||||||
|
if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
|
||||||
|
goto fault;
|
||||||
|
|
||||||
|
pte = pte_offset_map(pmd, uaddr);
|
||||||
|
if (!pte || !pte_present(*pte))
|
||||||
|
goto fault;
|
||||||
|
|
||||||
|
pfn = pte_pfn(*pte);
|
||||||
|
if (!pfn_valid(pfn)) {
|
||||||
|
done = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = uaddr & (PAGE_SIZE-1);
|
||||||
|
addr = (char *)(pfn << PAGE_SHIFT) + offset;
|
||||||
|
len = min(count - done, PAGE_SIZE - offset);
|
||||||
|
len_str = strnlen(addr, len);
|
||||||
|
done += len_str;
|
||||||
|
uaddr += len_str;
|
||||||
|
} while ((len_str == len) && (done < count));
|
||||||
|
out:
|
||||||
|
spin_unlock(&mm->page_table_lock);
|
||||||
|
return done + 1;
|
||||||
|
fault:
|
||||||
|
spin_unlock(&mm->page_table_lock);
|
||||||
|
if (__handle_fault(mm, uaddr, 0)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t strncpy_from_user_pt(size_t count, const char __user *src,
|
||||||
|
char *dst)
|
||||||
|
{
|
||||||
|
size_t n = strnlen_user_pt(count, src);
|
||||||
|
|
||||||
|
if (!n)
|
||||||
|
return -EFAULT;
|
||||||
|
if (n > count)
|
||||||
|
n = count;
|
||||||
|
if (segment_eq(get_fs(), KERNEL_DS)) {
|
||||||
|
memcpy(dst, (const char __kernel __force *) src, n);
|
||||||
|
if (dst[n-1] == '\0')
|
||||||
|
return n-1;
|
||||||
|
else
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
if (__user_copy_pt((unsigned long) src, dst, n, 0))
|
||||||
|
return -EFAULT;
|
||||||
|
if (dst[n-1] == '\0')
|
||||||
|
return n-1;
|
||||||
|
else
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t copy_in_user_pt(size_t n, void __user *to,
|
||||||
|
const void __user *from)
|
||||||
|
{
|
||||||
|
struct mm_struct *mm = current->mm;
|
||||||
|
unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to,
|
||||||
|
uaddr, done, size;
|
||||||
|
unsigned long uaddr_from = (unsigned long) from;
|
||||||
|
unsigned long uaddr_to = (unsigned long) to;
|
||||||
|
pgd_t *pgd_from, *pgd_to;
|
||||||
|
pmd_t *pmd_from, *pmd_to;
|
||||||
|
pte_t *pte_from, *pte_to;
|
||||||
|
int write_user;
|
||||||
|
|
||||||
|
done = 0;
|
||||||
|
retry:
|
||||||
|
spin_lock(&mm->page_table_lock);
|
||||||
|
do {
|
||||||
|
pgd_from = pgd_offset(mm, uaddr_from);
|
||||||
|
if (pgd_none(*pgd_from) || unlikely(pgd_bad(*pgd_from))) {
|
||||||
|
uaddr = uaddr_from;
|
||||||
|
write_user = 0;
|
||||||
|
goto fault;
|
||||||
|
}
|
||||||
|
pgd_to = pgd_offset(mm, uaddr_to);
|
||||||
|
if (pgd_none(*pgd_to) || unlikely(pgd_bad(*pgd_to))) {
|
||||||
|
uaddr = uaddr_to;
|
||||||
|
write_user = 1;
|
||||||
|
goto fault;
|
||||||
|
}
|
||||||
|
|
||||||
|
pmd_from = pmd_offset(pgd_from, uaddr_from);
|
||||||
|
if (pmd_none(*pmd_from) || unlikely(pmd_bad(*pmd_from))) {
|
||||||
|
uaddr = uaddr_from;
|
||||||
|
write_user = 0;
|
||||||
|
goto fault;
|
||||||
|
}
|
||||||
|
pmd_to = pmd_offset(pgd_to, uaddr_to);
|
||||||
|
if (pmd_none(*pmd_to) || unlikely(pmd_bad(*pmd_to))) {
|
||||||
|
uaddr = uaddr_to;
|
||||||
|
write_user = 1;
|
||||||
|
goto fault;
|
||||||
|
}
|
||||||
|
|
||||||
|
pte_from = pte_offset_map(pmd_from, uaddr_from);
|
||||||
|
if (!pte_from || !pte_present(*pte_from)) {
|
||||||
|
uaddr = uaddr_from;
|
||||||
|
write_user = 0;
|
||||||
|
goto fault;
|
||||||
|
}
|
||||||
|
pte_to = pte_offset_map(pmd_to, uaddr_to);
|
||||||
|
if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) {
|
||||||
|
uaddr = uaddr_to;
|
||||||
|
write_user = 1;
|
||||||
|
goto fault;
|
||||||
|
}
|
||||||
|
|
||||||
|
pfn_from = pte_pfn(*pte_from);
|
||||||
|
if (!pfn_valid(pfn_from))
|
||||||
|
goto out;
|
||||||
|
pfn_to = pte_pfn(*pte_to);
|
||||||
|
if (!pfn_valid(pfn_to))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
offset_from = uaddr_from & (PAGE_SIZE-1);
|
||||||
|
offset_to = uaddr_from & (PAGE_SIZE-1);
|
||||||
|
offset_max = max(offset_from, offset_to);
|
||||||
|
size = min(n - done, PAGE_SIZE - offset_max);
|
||||||
|
|
||||||
|
memcpy((void *)(pfn_to << PAGE_SHIFT) + offset_to,
|
||||||
|
(void *)(pfn_from << PAGE_SHIFT) + offset_from, size);
|
||||||
|
done += size;
|
||||||
|
uaddr_from += size;
|
||||||
|
uaddr_to += size;
|
||||||
|
} while (done < n);
|
||||||
|
out:
|
||||||
|
spin_unlock(&mm->page_table_lock);
|
||||||
|
return n - done;
|
||||||
|
fault:
|
||||||
|
spin_unlock(&mm->page_table_lock);
|
||||||
|
if (__handle_fault(mm, uaddr, write_user))
|
||||||
|
return n - done;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg) \
|
||||||
|
asm volatile("0: l %1,0(%6)\n" \
|
||||||
|
"1: " insn \
|
||||||
|
"2: cs %1,%2,0(%6)\n" \
|
||||||
|
"3: jl 1b\n" \
|
||||||
|
" lhi %0,0\n" \
|
||||||
|
"4:\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_pt(int op, int __user *uaddr, int oparg, int *old)
|
||||||
|
{
|
||||||
|
int oldval = 0, newval, ret;
|
||||||
|
|
||||||
|
spin_lock(¤t->mm->page_table_lock);
|
||||||
|
uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
|
||||||
|
if (!uaddr) {
|
||||||
|
spin_unlock(¤t->mm->page_table_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
get_page(virt_to_page(uaddr));
|
||||||
|
spin_unlock(¤t->mm->page_table_lock);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
put_page(virt_to_page(uaddr));
|
||||||
|
*old = oldval;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
spin_lock(¤t->mm->page_table_lock);
|
||||||
|
uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
|
||||||
|
if (!uaddr) {
|
||||||
|
spin_unlock(¤t->mm->page_table_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
get_page(virt_to_page(uaddr));
|
||||||
|
spin_unlock(¤t->mm->page_table_lock);
|
||||||
|
asm volatile(" cs %1,%4,0(%5)\n"
|
||||||
|
"0: lr %0,%1\n"
|
||||||
|
"1:\n"
|
||||||
|
EX_TABLE(0b,1b)
|
||||||
|
: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
|
||||||
|
: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
|
||||||
|
: "cc", "memory" );
|
||||||
|
put_page(virt_to_page(uaddr));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct uaccess_ops uaccess_pt = {
|
||||||
|
.copy_from_user = copy_from_user_pt,
|
||||||
|
.copy_from_user_small = copy_from_user_pt,
|
||||||
|
.copy_to_user = copy_to_user_pt,
|
||||||
|
.copy_to_user_small = copy_to_user_pt,
|
||||||
|
.copy_in_user = copy_in_user_pt,
|
||||||
|
.clear_user = clear_user_pt,
|
||||||
|
.strnlen_user = strnlen_user_pt,
|
||||||
|
.strncpy_from_user = strncpy_from_user_pt,
|
||||||
|
.futex_atomic_op = futex_atomic_op_pt,
|
||||||
|
.futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
|
||||||
|
};
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <asm/futex.h>
|
#include <asm/futex.h>
|
||||||
|
#include "uaccess.h"
|
||||||
|
|
||||||
#ifndef __s390x__
|
#ifndef __s390x__
|
||||||
#define AHI "ahi"
|
#define AHI "ahi"
|
||||||
|
@ -28,9 +29,6 @@
|
||||||
#define SLR "slgr"
|
#define SLR "slgr"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern size_t copy_from_user_pt(size_t n, const void __user *from, void *to);
|
|
||||||
extern size_t copy_to_user_pt(size_t n, void __user *to, const void *from);
|
|
||||||
|
|
||||||
size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
|
size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
|
||||||
{
|
{
|
||||||
unsigned long tmp1, tmp2;
|
unsigned long tmp1, tmp2;
|
||||||
|
@ -72,7 +70,8 @@ size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t copy_from_user_std_check(size_t size, const void __user *ptr, void *x)
|
static size_t copy_from_user_std_check(size_t size, const void __user *ptr,
|
||||||
|
void *x)
|
||||||
{
|
{
|
||||||
if (size <= 1024)
|
if (size <= 1024)
|
||||||
return copy_from_user_std(size, ptr, x);
|
return copy_from_user_std(size, ptr, x);
|
||||||
|
@ -110,14 +109,16 @@ size_t copy_to_user_std(size_t size, void __user *ptr, const void *x)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t copy_to_user_std_check(size_t size, void __user *ptr, const void *x)
|
static size_t copy_to_user_std_check(size_t size, void __user *ptr,
|
||||||
|
const void *x)
|
||||||
{
|
{
|
||||||
if (size <= 1024)
|
if (size <= 1024)
|
||||||
return copy_to_user_std(size, ptr, x);
|
return copy_to_user_std(size, ptr, x);
|
||||||
return copy_to_user_pt(size, ptr, x);
|
return copy_to_user_pt(size, ptr, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t copy_in_user_std(size_t size, void __user *to, const void __user *from)
|
static size_t copy_in_user_std(size_t size, void __user *to,
|
||||||
|
const void __user *from)
|
||||||
{
|
{
|
||||||
unsigned long tmp1;
|
unsigned long tmp1;
|
||||||
|
|
||||||
|
@ -148,7 +149,7 @@ size_t copy_in_user_std(size_t size, void __user *to, const void __user *from)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t clear_user_std(size_t size, void __user *to)
|
static size_t clear_user_std(size_t size, void __user *to)
|
||||||
{
|
{
|
||||||
unsigned long tmp1, tmp2;
|
unsigned long tmp1, tmp2;
|
||||||
|
|
||||||
|
@ -254,7 +255,7 @@ size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
|
||||||
: "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
|
: "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
|
||||||
"m" (*uaddr) : "cc");
|
"m" (*uaddr) : "cc");
|
||||||
|
|
||||||
int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old)
|
int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
|
||||||
{
|
{
|
||||||
int oldval = 0, newval, ret;
|
int oldval = 0, newval, ret;
|
||||||
|
|
||||||
|
@ -286,7 +287,7 @@ int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval)
|
int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -311,6 +312,6 @@ struct uaccess_ops uaccess_std = {
|
||||||
.clear_user = clear_user_std,
|
.clear_user = clear_user_std,
|
||||||
.strnlen_user = strnlen_user_std,
|
.strnlen_user = strnlen_user_std,
|
||||||
.strncpy_from_user = strncpy_from_user_std,
|
.strncpy_from_user = strncpy_from_user_std,
|
||||||
.futex_atomic_op = futex_atomic_op,
|
.futex_atomic_op = futex_atomic_op_std,
|
||||||
.futex_atomic_cmpxchg = futex_atomic_cmpxchg,
|
.futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# Makefile for the FPU instruction emulation.
|
# Makefile for the FPU instruction emulation.
|
||||||
#
|
#
|
||||||
|
|
||||||
obj-$(CONFIG_MATHEMU) := math.o qrnnd.o
|
obj-$(CONFIG_MATHEMU) := math.o
|
||||||
|
|
||||||
EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
|
EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
|
||||||
EXTRA_AFLAGS := -traditional
|
EXTRA_AFLAGS := -traditional
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/lowcore.h>
|
#include <asm/lowcore.h>
|
||||||
|
|
||||||
#include "sfp-util.h"
|
#include <asm/sfp-util.h>
|
||||||
#include <math-emu/soft-fp.h>
|
#include <math-emu/soft-fp.h>
|
||||||
#include <math-emu/single.h>
|
#include <math-emu/single.h>
|
||||||
#include <math-emu/double.h>
|
#include <math-emu/double.h>
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
# S/390 __udiv_qrnnd
|
|
||||||
|
|
||||||
# r2 : &__r
|
|
||||||
# r3 : upper half of 64 bit word n
|
|
||||||
# r4 : lower half of 64 bit word n
|
|
||||||
# r5 : divisor d
|
|
||||||
# the reminder r of the division is to be stored to &__r and
|
|
||||||
# the quotient q is to be returned
|
|
||||||
|
|
||||||
.text
|
|
||||||
.globl __udiv_qrnnd
|
|
||||||
__udiv_qrnnd:
|
|
||||||
st %r2,24(%r15) # store pointer to reminder for later
|
|
||||||
lr %r0,%r3 # reload n
|
|
||||||
lr %r1,%r4
|
|
||||||
ltr %r2,%r5 # reload and test divisor
|
|
||||||
jp 5f
|
|
||||||
# divisor >= 0x80000000
|
|
||||||
srdl %r0,2 # n/4
|
|
||||||
srl %r2,1 # d/2
|
|
||||||
slr %r1,%r2 # special case if last bit of d is set
|
|
||||||
brc 3,0f # (n/4) div (n/2) can overflow by 1
|
|
||||||
ahi %r0,-1 # trick: subtract n/2, then divide
|
|
||||||
0: dr %r0,%r2 # signed division
|
|
||||||
ahi %r1,1 # trick part 2: add 1 to the quotient
|
|
||||||
# now (n >> 2) = (d >> 1) * %r1 + %r0
|
|
||||||
lhi %r3,1
|
|
||||||
nr %r3,%r1 # test last bit of q
|
|
||||||
jz 1f
|
|
||||||
alr %r0,%r2 # add (d>>1) to r
|
|
||||||
1: srl %r1,1 # q >>= 1
|
|
||||||
# now (n >> 2) = (d&-2) * %r1 + %r0
|
|
||||||
lhi %r3,1
|
|
||||||
nr %r3,%r5 # test last bit of d
|
|
||||||
jz 2f
|
|
||||||
slr %r0,%r1 # r -= q
|
|
||||||
brc 3,2f # borrow ?
|
|
||||||
alr %r0,%r5 # r += d
|
|
||||||
ahi %r1,-1
|
|
||||||
2: # now (n >> 2) = d * %r1 + %r0
|
|
||||||
alr %r1,%r1 # q <<= 1
|
|
||||||
alr %r0,%r0 # r <<= 1
|
|
||||||
brc 12,3f # overflow on r ?
|
|
||||||
slr %r0,%r5 # r -= d
|
|
||||||
ahi %r1,1 # q += 1
|
|
||||||
3: lhi %r3,2
|
|
||||||
nr %r3,%r4 # test next to last bit of n
|
|
||||||
jz 4f
|
|
||||||
ahi %r0,1 # r += 1
|
|
||||||
4: clr %r0,%r5 # r >= d ?
|
|
||||||
jl 6f
|
|
||||||
slr %r0,%r5 # r -= d
|
|
||||||
ahi %r1,1 # q += 1
|
|
||||||
# now (n >> 1) = d * %r1 + %r0
|
|
||||||
j 6f
|
|
||||||
5: # divisor < 0x80000000
|
|
||||||
srdl %r0,1
|
|
||||||
dr %r0,%r2 # signed division
|
|
||||||
# now (n >> 1) = d * %r1 + %r0
|
|
||||||
6: alr %r1,%r1 # q <<= 1
|
|
||||||
alr %r0,%r0 # r <<= 1
|
|
||||||
brc 12,7f # overflow on r ?
|
|
||||||
slr %r0,%r5 # r -= d
|
|
||||||
ahi %r1,1 # q += 1
|
|
||||||
7: lhi %r3,1
|
|
||||||
nr %r3,%r4 # isolate last bit of n
|
|
||||||
alr %r0,%r3 # r += (n & 1)
|
|
||||||
clr %r0,%r5 # r >= d ?
|
|
||||||
jl 8f
|
|
||||||
slr %r0,%r5 # r -= d
|
|
||||||
ahi %r1,1 # q += 1
|
|
||||||
8: # now n = d * %r1 + %r0
|
|
||||||
l %r2,24(%r15)
|
|
||||||
st %r0,0(%r2)
|
|
||||||
lr %r2,%r1
|
|
||||||
br %r14
|
|
||||||
.end __udiv_qrnnd
|
|
|
@ -245,7 +245,7 @@ cmm_set_timeout(long nr, long seconds)
|
||||||
cmm_set_timer();
|
cmm_set_timer();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static int
|
||||||
cmm_skip_blanks(char *cp, char **endp)
|
cmm_skip_blanks(char *cp, char **endp)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
|
@ -414,7 +414,7 @@ cmm_smsg_target(char *from, char *msg)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct ctl_table_header *cmm_sysctl_header;
|
static struct ctl_table_header *cmm_sysctl_header;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cmm_init (void)
|
cmm_init (void)
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/bootmem.h>
|
#include <linux/bootmem.h>
|
||||||
#include <linux/ctype.h>
|
#include <linux/ctype.h>
|
||||||
|
#include <linux/ioport.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/ebcdic.h>
|
#include <asm/ebcdic.h>
|
||||||
|
@ -70,6 +71,7 @@ struct qin64 {
|
||||||
struct dcss_segment {
|
struct dcss_segment {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
char dcss_name[8];
|
char dcss_name[8];
|
||||||
|
char res_name[15];
|
||||||
unsigned long start_addr;
|
unsigned long start_addr;
|
||||||
unsigned long end;
|
unsigned long end;
|
||||||
atomic_t ref_count;
|
atomic_t ref_count;
|
||||||
|
@ -77,6 +79,7 @@ struct dcss_segment {
|
||||||
unsigned int vm_segtype;
|
unsigned int vm_segtype;
|
||||||
struct qrange range[6];
|
struct qrange range[6];
|
||||||
int segcnt;
|
int segcnt;
|
||||||
|
struct resource *res;
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFINE_MUTEX(dcss_lock);
|
static DEFINE_MUTEX(dcss_lock);
|
||||||
|
@ -88,7 +91,7 @@ static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
|
||||||
* Create the 8 bytes, ebcdic VM segment name from
|
* Create the 8 bytes, ebcdic VM segment name from
|
||||||
* an ascii name.
|
* an ascii name.
|
||||||
*/
|
*/
|
||||||
static void inline
|
static void
|
||||||
dcss_mkname(char *name, char *dcss_name)
|
dcss_mkname(char *name, char *dcss_name)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -303,6 +306,29 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
|
||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL);
|
||||||
|
if (seg->res == NULL) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto out_shared;
|
||||||
|
}
|
||||||
|
seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
|
||||||
|
seg->res->start = seg->start_addr;
|
||||||
|
seg->res->end = seg->end;
|
||||||
|
memcpy(&seg->res_name, seg->dcss_name, 8);
|
||||||
|
EBCASC(seg->res_name, 8);
|
||||||
|
seg->res_name[8] = '\0';
|
||||||
|
strncat(seg->res_name, " (DCSS)", 7);
|
||||||
|
seg->res->name = seg->res_name;
|
||||||
|
rc = seg->vm_segtype;
|
||||||
|
if (rc == SEG_TYPE_SC ||
|
||||||
|
((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
|
||||||
|
seg->res->flags |= IORESOURCE_READONLY;
|
||||||
|
if (request_resource(&iomem_resource, seg->res)) {
|
||||||
|
rc = -EBUSY;
|
||||||
|
kfree(seg->res);
|
||||||
|
goto out_shared;
|
||||||
|
}
|
||||||
|
|
||||||
if (do_nonshared)
|
if (do_nonshared)
|
||||||
dcss_command = DCSS_LOADNSR;
|
dcss_command = DCSS_LOADNSR;
|
||||||
else
|
else
|
||||||
|
@ -316,12 +342,11 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
|
||||||
rc = dcss_diag_translate_rc (seg->end);
|
rc = dcss_diag_translate_rc (seg->end);
|
||||||
dcss_diag(DCSS_PURGESEG, seg->dcss_name,
|
dcss_diag(DCSS_PURGESEG, seg->dcss_name,
|
||||||
&seg->start_addr, &seg->end);
|
&seg->start_addr, &seg->end);
|
||||||
goto out_shared;
|
goto out_resource;
|
||||||
}
|
}
|
||||||
seg->do_nonshared = do_nonshared;
|
seg->do_nonshared = do_nonshared;
|
||||||
atomic_set(&seg->ref_count, 1);
|
atomic_set(&seg->ref_count, 1);
|
||||||
list_add(&seg->list, &dcss_list);
|
list_add(&seg->list, &dcss_list);
|
||||||
rc = seg->vm_segtype;
|
|
||||||
*addr = seg->start_addr;
|
*addr = seg->start_addr;
|
||||||
*end = seg->end;
|
*end = seg->end;
|
||||||
if (do_nonshared)
|
if (do_nonshared)
|
||||||
|
@ -329,12 +354,16 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
|
||||||
"type %s in non-shared mode\n", name,
|
"type %s in non-shared mode\n", name,
|
||||||
(void*)seg->start_addr, (void*)seg->end,
|
(void*)seg->start_addr, (void*)seg->end,
|
||||||
segtype_string[seg->vm_segtype]);
|
segtype_string[seg->vm_segtype]);
|
||||||
else
|
else {
|
||||||
PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
|
PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
|
||||||
"type %s in shared mode\n", name,
|
"type %s in shared mode\n", name,
|
||||||
(void*)seg->start_addr, (void*)seg->end,
|
(void*)seg->start_addr, (void*)seg->end,
|
||||||
segtype_string[seg->vm_segtype]);
|
segtype_string[seg->vm_segtype]);
|
||||||
|
}
|
||||||
goto out;
|
goto out;
|
||||||
|
out_resource:
|
||||||
|
release_resource(seg->res);
|
||||||
|
kfree(seg->res);
|
||||||
out_shared:
|
out_shared:
|
||||||
remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
|
remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
|
||||||
out_free:
|
out_free:
|
||||||
|
@ -401,6 +430,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr,
|
||||||
* -ENOENT : no such segment (segment gone!)
|
* -ENOENT : no such segment (segment gone!)
|
||||||
* -EAGAIN : segment is in use by other exploiters, try later
|
* -EAGAIN : segment is in use by other exploiters, try later
|
||||||
* -EINVAL : no segment with the given name is currently loaded - name invalid
|
* -EINVAL : no segment with the given name is currently loaded - name invalid
|
||||||
|
* -EBUSY : segment can temporarily not be used (overlaps with dcss)
|
||||||
* 0 : operation succeeded
|
* 0 : operation succeeded
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
|
@ -428,12 +458,24 @@ segment_modify_shared (char *name, int do_nonshared)
|
||||||
rc = -EAGAIN;
|
rc = -EAGAIN;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
dcss_diag(DCSS_PURGESEG, seg->dcss_name,
|
release_resource(seg->res);
|
||||||
&dummy, &dummy);
|
if (do_nonshared) {
|
||||||
if (do_nonshared)
|
|
||||||
dcss_command = DCSS_LOADNSR;
|
dcss_command = DCSS_LOADNSR;
|
||||||
else
|
seg->res->flags &= ~IORESOURCE_READONLY;
|
||||||
dcss_command = DCSS_LOADNOLY;
|
} else {
|
||||||
|
dcss_command = DCSS_LOADNOLY;
|
||||||
|
if (seg->vm_segtype == SEG_TYPE_SR ||
|
||||||
|
seg->vm_segtype == SEG_TYPE_ER)
|
||||||
|
seg->res->flags |= IORESOURCE_READONLY;
|
||||||
|
}
|
||||||
|
if (request_resource(&iomem_resource, seg->res)) {
|
||||||
|
PRINT_WARN("segment_modify_shared: could not reload segment %s"
|
||||||
|
" - overlapping resources\n", name);
|
||||||
|
rc = -EBUSY;
|
||||||
|
kfree(seg->res);
|
||||||
|
goto out_del;
|
||||||
|
}
|
||||||
|
dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
|
||||||
diag_cc = dcss_diag(dcss_command, seg->dcss_name,
|
diag_cc = dcss_diag(dcss_command, seg->dcss_name,
|
||||||
&seg->start_addr, &seg->end);
|
&seg->start_addr, &seg->end);
|
||||||
if (diag_cc > 1) {
|
if (diag_cc > 1) {
|
||||||
|
@ -446,9 +488,9 @@ segment_modify_shared (char *name, int do_nonshared)
|
||||||
rc = 0;
|
rc = 0;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
out_del:
|
out_del:
|
||||||
|
remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
|
||||||
list_del(&seg->list);
|
list_del(&seg->list);
|
||||||
dcss_diag(DCSS_PURGESEG, seg->dcss_name,
|
dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
|
||||||
&dummy, &dummy);
|
|
||||||
kfree(seg);
|
kfree(seg);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&dcss_lock);
|
mutex_unlock(&dcss_lock);
|
||||||
|
@ -478,6 +520,8 @@ segment_unload(char *name)
|
||||||
}
|
}
|
||||||
if (atomic_dec_return(&seg->ref_count) != 0)
|
if (atomic_dec_return(&seg->ref_count) != 0)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
release_resource(seg->res);
|
||||||
|
kfree(seg->res);
|
||||||
remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
|
remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
|
||||||
list_del(&seg->list);
|
list_del(&seg->list);
|
||||||
dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
|
dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
|
||||||
|
|
|
@ -52,7 +52,7 @@ extern int sysctl_userprocess_debug;
|
||||||
extern void die(const char *,struct pt_regs *,long);
|
extern void die(const char *,struct pt_regs *,long);
|
||||||
|
|
||||||
#ifdef CONFIG_KPROBES
|
#ifdef CONFIG_KPROBES
|
||||||
ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
|
static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
|
||||||
int register_page_fault_notifier(struct notifier_block *nb)
|
int register_page_fault_notifier(struct notifier_block *nb)
|
||||||
{
|
{
|
||||||
return atomic_notifier_chain_register(¬ify_page_fault_chain, nb);
|
return atomic_notifier_chain_register(¬ify_page_fault_chain, nb);
|
||||||
|
@ -137,7 +137,9 @@ static int __check_access_register(struct pt_regs *regs, int error_code)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check which address space the address belongs to.
|
* Check which address space the address belongs to.
|
||||||
* Returns 1 for user space and 0 for kernel space.
|
* May return 1 or 2 for user space and 0 for kernel space.
|
||||||
|
* Returns 2 for user space in primary addressing mode with
|
||||||
|
* CONFIG_S390_EXEC_PROTECT on and kernel parameter noexec=on.
|
||||||
*/
|
*/
|
||||||
static inline int check_user_space(struct pt_regs *regs, int error_code)
|
static inline int check_user_space(struct pt_regs *regs, int error_code)
|
||||||
{
|
{
|
||||||
|
@ -154,7 +156,7 @@ static inline int check_user_space(struct pt_regs *regs, int error_code)
|
||||||
return __check_access_register(regs, error_code);
|
return __check_access_register(regs, error_code);
|
||||||
if (descriptor == 2)
|
if (descriptor == 2)
|
||||||
return current->thread.mm_segment.ar4;
|
return current->thread.mm_segment.ar4;
|
||||||
return descriptor != 0;
|
return ((descriptor != 0) ^ (switch_amode)) << s390_noexec;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -183,6 +185,77 @@ static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
|
||||||
force_sig_info(SIGSEGV, &si, current);
|
force_sig_info(SIGSEGV, &si, current);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_S390_EXEC_PROTECT
|
||||||
|
extern long sys_sigreturn(struct pt_regs *regs);
|
||||||
|
extern long sys_rt_sigreturn(struct pt_regs *regs);
|
||||||
|
extern long sys32_sigreturn(struct pt_regs *regs);
|
||||||
|
extern long sys32_rt_sigreturn(struct pt_regs *regs);
|
||||||
|
|
||||||
|
static inline void do_sigreturn(struct mm_struct *mm, struct pt_regs *regs,
|
||||||
|
int rt)
|
||||||
|
{
|
||||||
|
up_read(&mm->mmap_sem);
|
||||||
|
clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
if (test_tsk_thread_flag(current, TIF_31BIT)) {
|
||||||
|
if (rt)
|
||||||
|
sys32_rt_sigreturn(regs);
|
||||||
|
else
|
||||||
|
sys32_sigreturn(regs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_COMPAT */
|
||||||
|
if (rt)
|
||||||
|
sys_rt_sigreturn(regs);
|
||||||
|
else
|
||||||
|
sys_sigreturn(regs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
|
||||||
|
unsigned long address, unsigned long error_code)
|
||||||
|
{
|
||||||
|
pgd_t *pgd;
|
||||||
|
pmd_t *pmd;
|
||||||
|
pte_t *pte;
|
||||||
|
u16 *instruction;
|
||||||
|
unsigned long pfn, uaddr = regs->psw.addr;
|
||||||
|
|
||||||
|
spin_lock(&mm->page_table_lock);
|
||||||
|
pgd = pgd_offset(mm, uaddr);
|
||||||
|
if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
|
||||||
|
goto out_fault;
|
||||||
|
pmd = pmd_offset(pgd, uaddr);
|
||||||
|
if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
|
||||||
|
goto out_fault;
|
||||||
|
pte = pte_offset_map(pmd_offset(pgd_offset(mm, uaddr), uaddr), uaddr);
|
||||||
|
if (!pte || !pte_present(*pte))
|
||||||
|
goto out_fault;
|
||||||
|
pfn = pte_pfn(*pte);
|
||||||
|
if (!pfn_valid(pfn))
|
||||||
|
goto out_fault;
|
||||||
|
spin_unlock(&mm->page_table_lock);
|
||||||
|
|
||||||
|
instruction = (u16 *) ((pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE-1)));
|
||||||
|
if (*instruction == 0x0a77)
|
||||||
|
do_sigreturn(mm, regs, 0);
|
||||||
|
else if (*instruction == 0x0aad)
|
||||||
|
do_sigreturn(mm, regs, 1);
|
||||||
|
else {
|
||||||
|
printk("- XXX - do_exception: task = %s, primary, NO EXEC "
|
||||||
|
"-> SIGSEGV\n", current->comm);
|
||||||
|
up_read(&mm->mmap_sem);
|
||||||
|
current->thread.prot_addr = address;
|
||||||
|
current->thread.trap_no = error_code;
|
||||||
|
do_sigsegv(regs, error_code, SEGV_MAPERR, address);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
out_fault:
|
||||||
|
spin_unlock(&mm->page_table_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_S390_EXEC_PROTECT */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This routine handles page faults. It determines the address,
|
* This routine handles page faults. It determines the address,
|
||||||
* and the problem, and then passes it off to one of the appropriate
|
* and the problem, and then passes it off to one of the appropriate
|
||||||
|
@ -260,6 +333,17 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
|
||||||
vma = find_vma(mm, address);
|
vma = find_vma(mm, address);
|
||||||
if (!vma)
|
if (!vma)
|
||||||
goto bad_area;
|
goto bad_area;
|
||||||
|
|
||||||
|
#ifdef CONFIG_S390_EXEC_PROTECT
|
||||||
|
if (unlikely((user_address == 2) && !(vma->vm_flags & VM_EXEC)))
|
||||||
|
if (!signal_return(mm, regs, address, error_code))
|
||||||
|
/*
|
||||||
|
* signal_return() has done an up_read(&mm->mmap_sem)
|
||||||
|
* if it returns 0.
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (vma->vm_start <= address)
|
if (vma->vm_start <= address)
|
||||||
goto good_area;
|
goto good_area;
|
||||||
if (!(vma->vm_flags & VM_GROWSDOWN))
|
if (!(vma->vm_flags & VM_GROWSDOWN))
|
||||||
|
@ -452,8 +536,7 @@ void pfault_fini(void)
|
||||||
: : "a" (&refbk), "m" (refbk) : "cc");
|
: : "a" (&refbk), "m" (refbk) : "cc");
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage void
|
static void pfault_interrupt(__u16 error_code)
|
||||||
pfault_interrupt(__u16 error_code)
|
|
||||||
{
|
{
|
||||||
struct task_struct *tsk;
|
struct task_struct *tsk;
|
||||||
__u16 subcode;
|
__u16 subcode;
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include <linux/bootmem.h>
|
#include <linux/bootmem.h>
|
||||||
#include <linux/pfn.h>
|
#include <linux/pfn.h>
|
||||||
#include <linux/poison.h>
|
#include <linux/poison.h>
|
||||||
|
#include <linux/initrd.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
|
@ -95,20 +95,18 @@ static void __init setup_ro_region(void)
|
||||||
pte_t new_pte;
|
pte_t new_pte;
|
||||||
unsigned long address, end;
|
unsigned long address, end;
|
||||||
|
|
||||||
address = ((unsigned long)&__start_rodata) & PAGE_MASK;
|
address = ((unsigned long)&_stext) & PAGE_MASK;
|
||||||
end = PFN_ALIGN((unsigned long)&__end_rodata);
|
end = PFN_ALIGN((unsigned long)&_eshared);
|
||||||
|
|
||||||
for (; address < end; address += PAGE_SIZE) {
|
for (; address < end; address += PAGE_SIZE) {
|
||||||
pgd = pgd_offset_k(address);
|
pgd = pgd_offset_k(address);
|
||||||
pmd = pmd_offset(pgd, address);
|
pmd = pmd_offset(pgd, address);
|
||||||
pte = pte_offset_kernel(pmd, address);
|
pte = pte_offset_kernel(pmd, address);
|
||||||
new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO));
|
new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO));
|
||||||
set_pte(pte, new_pte);
|
*pte = new_pte;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void vmem_map_init(void);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* paging_init() sets up the page tables
|
* paging_init() sets up the page tables
|
||||||
*/
|
*/
|
||||||
|
@ -125,11 +123,11 @@ void __init paging_init(void)
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE;
|
pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE;
|
||||||
for (i = 0; i < PTRS_PER_PGD; i++)
|
for (i = 0; i < PTRS_PER_PGD; i++)
|
||||||
pgd_clear(pg_dir + i);
|
pgd_clear_kernel(pg_dir + i);
|
||||||
#else
|
#else
|
||||||
pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
|
pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
|
||||||
for (i = 0; i < PTRS_PER_PGD; i++)
|
for (i = 0; i < PTRS_PER_PGD; i++)
|
||||||
pmd_clear((pmd_t *)(pg_dir + i));
|
pmd_clear_kernel((pmd_t *)(pg_dir + i));
|
||||||
#endif
|
#endif
|
||||||
vmem_map_init();
|
vmem_map_init();
|
||||||
setup_ro_region();
|
setup_ro_region();
|
||||||
|
@ -174,10 +172,8 @@ void __init mem_init(void)
|
||||||
datasize >>10,
|
datasize >>10,
|
||||||
initsize >> 10);
|
initsize >> 10);
|
||||||
printk("Write protected kernel read-only data: %#lx - %#lx\n",
|
printk("Write protected kernel read-only data: %#lx - %#lx\n",
|
||||||
(unsigned long)&__start_rodata,
|
(unsigned long)&_stext,
|
||||||
PFN_ALIGN((unsigned long)&__end_rodata) - 1);
|
PFN_ALIGN((unsigned long)&_eshared) - 1);
|
||||||
printk("Virtual memmap size: %ldk\n",
|
|
||||||
(max_pfn * sizeof(struct page)) >> 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_initmem(void)
|
void free_initmem(void)
|
||||||
|
|
|
@ -82,7 +82,7 @@ static inline pmd_t *vmem_pmd_alloc(void)
|
||||||
if (!pmd)
|
if (!pmd)
|
||||||
return NULL;
|
return NULL;
|
||||||
for (i = 0; i < PTRS_PER_PMD; i++)
|
for (i = 0; i < PTRS_PER_PMD; i++)
|
||||||
pmd_clear(pmd + i);
|
pmd_clear_kernel(pmd + i);
|
||||||
return pmd;
|
return pmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,7 @@ static inline pte_t *vmem_pte_alloc(void)
|
||||||
return NULL;
|
return NULL;
|
||||||
pte_val(empty_pte) = _PAGE_TYPE_EMPTY;
|
pte_val(empty_pte) = _PAGE_TYPE_EMPTY;
|
||||||
for (i = 0; i < PTRS_PER_PTE; i++)
|
for (i = 0; i < PTRS_PER_PTE; i++)
|
||||||
set_pte(pte + i, empty_pte);
|
pte[i] = empty_pte;
|
||||||
return pte;
|
return pte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ static int vmem_add_range(unsigned long start, unsigned long size)
|
||||||
pm_dir = vmem_pmd_alloc();
|
pm_dir = vmem_pmd_alloc();
|
||||||
if (!pm_dir)
|
if (!pm_dir)
|
||||||
goto out;
|
goto out;
|
||||||
pgd_populate(&init_mm, pg_dir, pm_dir);
|
pgd_populate_kernel(&init_mm, pg_dir, pm_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_dir = pmd_offset(pg_dir, address);
|
pm_dir = pmd_offset(pg_dir, address);
|
||||||
|
@ -132,7 +132,7 @@ static int vmem_add_range(unsigned long start, unsigned long size)
|
||||||
|
|
||||||
pt_dir = pte_offset_kernel(pm_dir, address);
|
pt_dir = pte_offset_kernel(pm_dir, address);
|
||||||
pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL);
|
pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL);
|
||||||
set_pte(pt_dir, pte);
|
*pt_dir = pte;
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
|
@ -161,7 +161,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
|
||||||
if (pmd_none(*pm_dir))
|
if (pmd_none(*pm_dir))
|
||||||
continue;
|
continue;
|
||||||
pt_dir = pte_offset_kernel(pm_dir, address);
|
pt_dir = pte_offset_kernel(pm_dir, address);
|
||||||
set_pte(pt_dir, pte);
|
*pt_dir = pte;
|
||||||
}
|
}
|
||||||
flush_tlb_kernel_range(start, start + size);
|
flush_tlb_kernel_range(start, start + size);
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size)
|
||||||
pm_dir = vmem_pmd_alloc();
|
pm_dir = vmem_pmd_alloc();
|
||||||
if (!pm_dir)
|
if (!pm_dir)
|
||||||
goto out;
|
goto out;
|
||||||
pgd_populate(&init_mm, pg_dir, pm_dir);
|
pgd_populate_kernel(&init_mm, pg_dir, pm_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
pm_dir = pmd_offset(pg_dir, address);
|
pm_dir = pmd_offset(pg_dir, address);
|
||||||
|
@ -210,7 +210,7 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size)
|
||||||
if (!new_page)
|
if (!new_page)
|
||||||
goto out;
|
goto out;
|
||||||
pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL);
|
pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL);
|
||||||
set_pte(pt_dir, pte);
|
*pt_dir = pte;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
|
@ -74,14 +74,6 @@ config CRYPTO_SHA1
|
||||||
help
|
help
|
||||||
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
|
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
|
||||||
|
|
||||||
config CRYPTO_SHA1_S390
|
|
||||||
tristate "SHA1 digest algorithm (s390)"
|
|
||||||
depends on S390
|
|
||||||
select CRYPTO_ALGAPI
|
|
||||||
help
|
|
||||||
This is the s390 hardware accelerated implementation of the
|
|
||||||
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
|
|
||||||
|
|
||||||
config CRYPTO_SHA256
|
config CRYPTO_SHA256
|
||||||
tristate "SHA256 digest algorithm"
|
tristate "SHA256 digest algorithm"
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
|
@ -91,17 +83,6 @@ config CRYPTO_SHA256
|
||||||
This version of SHA implements a 256 bit hash with 128 bits of
|
This version of SHA implements a 256 bit hash with 128 bits of
|
||||||
security against collision attacks.
|
security against collision attacks.
|
||||||
|
|
||||||
config CRYPTO_SHA256_S390
|
|
||||||
tristate "SHA256 digest algorithm (s390)"
|
|
||||||
depends on S390
|
|
||||||
select CRYPTO_ALGAPI
|
|
||||||
help
|
|
||||||
This is the s390 hardware accelerated implementation of the
|
|
||||||
SHA256 secure hash standard (DFIPS 180-2).
|
|
||||||
|
|
||||||
This version of SHA implements a 256 bit hash with 128 bits of
|
|
||||||
security against collision attacks.
|
|
||||||
|
|
||||||
config CRYPTO_SHA512
|
config CRYPTO_SHA512
|
||||||
tristate "SHA384 and SHA512 digest algorithms"
|
tristate "SHA384 and SHA512 digest algorithms"
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
|
@ -187,14 +168,6 @@ config CRYPTO_DES
|
||||||
help
|
help
|
||||||
DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
|
DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
|
||||||
|
|
||||||
config CRYPTO_DES_S390
|
|
||||||
tristate "DES and Triple DES cipher algorithms (s390)"
|
|
||||||
depends on S390
|
|
||||||
select CRYPTO_ALGAPI
|
|
||||||
select CRYPTO_BLKCIPHER
|
|
||||||
help
|
|
||||||
DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
|
|
||||||
|
|
||||||
config CRYPTO_BLOWFISH
|
config CRYPTO_BLOWFISH
|
||||||
tristate "Blowfish cipher algorithm"
|
tristate "Blowfish cipher algorithm"
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
|
@ -336,28 +309,6 @@ config CRYPTO_AES_X86_64
|
||||||
|
|
||||||
See <http://csrc.nist.gov/encryption/aes/> for more information.
|
See <http://csrc.nist.gov/encryption/aes/> for more information.
|
||||||
|
|
||||||
config CRYPTO_AES_S390
|
|
||||||
tristate "AES cipher algorithms (s390)"
|
|
||||||
depends on S390
|
|
||||||
select CRYPTO_ALGAPI
|
|
||||||
select CRYPTO_BLKCIPHER
|
|
||||||
help
|
|
||||||
This is the s390 hardware accelerated implementation of the
|
|
||||||
AES cipher algorithms (FIPS-197). AES uses the Rijndael
|
|
||||||
algorithm.
|
|
||||||
|
|
||||||
Rijndael appears to be consistently a very good performer in
|
|
||||||
both hardware and software across a wide range of computing
|
|
||||||
environments regardless of its use in feedback or non-feedback
|
|
||||||
modes. Its key setup time is excellent, and its key agility is
|
|
||||||
good. Rijndael's very low memory requirements make it very well
|
|
||||||
suited for restricted-space environments, in which it also
|
|
||||||
demonstrates excellent performance. Rijndael's operations are
|
|
||||||
among the easiest to defend against power and timing attacks.
|
|
||||||
|
|
||||||
On s390 the System z9-109 currently only supports the key size
|
|
||||||
of 128 bit.
|
|
||||||
|
|
||||||
config CRYPTO_CAST5
|
config CRYPTO_CAST5
|
||||||
tristate "CAST5 (CAST-128) cipher algorithm"
|
tristate "CAST5 (CAST-128) cipher algorithm"
|
||||||
select CRYPTO_ALGAPI
|
select CRYPTO_ALGAPI
|
||||||
|
|
|
@ -51,6 +51,8 @@ config CRYPTO_DEV_PADLOCK_SHA
|
||||||
If unsure say M. The compiled module will be
|
If unsure say M. The compiled module will be
|
||||||
called padlock-sha.ko
|
called padlock-sha.ko
|
||||||
|
|
||||||
|
source "arch/s390/crypto/Kconfig"
|
||||||
|
|
||||||
config CRYPTO_DEV_GEODE
|
config CRYPTO_DEV_GEODE
|
||||||
tristate "Support for the Geode LX AES engine"
|
tristate "Support for the Geode LX AES engine"
|
||||||
depends on CRYPTO && X86_32 && PCI
|
depends on CRYPTO && X86_32 && PCI
|
||||||
|
|
|
@ -103,14 +103,8 @@ config CCW_CONSOLE
|
||||||
depends on TN3215_CONSOLE || TN3270_CONSOLE
|
depends on TN3215_CONSOLE || TN3270_CONSOLE
|
||||||
default y
|
default y
|
||||||
|
|
||||||
config SCLP
|
|
||||||
bool "Support for SCLP"
|
|
||||||
help
|
|
||||||
Include support for the SCLP interface to the service element.
|
|
||||||
|
|
||||||
config SCLP_TTY
|
config SCLP_TTY
|
||||||
bool "Support for SCLP line mode terminal"
|
bool "Support for SCLP line mode terminal"
|
||||||
depends on SCLP
|
|
||||||
help
|
help
|
||||||
Include support for IBM SCLP line-mode terminals.
|
Include support for IBM SCLP line-mode terminals.
|
||||||
|
|
||||||
|
@ -123,7 +117,6 @@ config SCLP_CONSOLE
|
||||||
|
|
||||||
config SCLP_VT220_TTY
|
config SCLP_VT220_TTY
|
||||||
bool "Support for SCLP VT220-compatible terminal"
|
bool "Support for SCLP VT220-compatible terminal"
|
||||||
depends on SCLP
|
|
||||||
help
|
help
|
||||||
Include support for an IBM SCLP VT220-compatible terminal.
|
Include support for an IBM SCLP VT220-compatible terminal.
|
||||||
|
|
||||||
|
@ -136,7 +129,6 @@ config SCLP_VT220_CONSOLE
|
||||||
|
|
||||||
config SCLP_CPI
|
config SCLP_CPI
|
||||||
tristate "Control-Program Identification"
|
tristate "Control-Program Identification"
|
||||||
depends on SCLP
|
|
||||||
help
|
help
|
||||||
This option enables the hardware console interface for system
|
This option enables the hardware console interface for system
|
||||||
identification. This is commonly used for workload management and
|
identification. This is commonly used for workload management and
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
# Makefile for the S/390 specific device drivers
|
# Makefile for the S/390 specific device drivers
|
||||||
#
|
#
|
||||||
|
|
||||||
|
CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
|
||||||
|
|
||||||
obj-y += s390mach.o sysinfo.o s390_rdev.o
|
obj-y += s390mach.o sysinfo.o s390_rdev.o
|
||||||
obj-y += cio/ block/ char/ crypto/ net/ scsi/
|
obj-y += cio/ block/ char/ crypto/ net/ scsi/
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
*/
|
*/
|
||||||
debug_info_t *dasd_debug_area;
|
debug_info_t *dasd_debug_area;
|
||||||
struct dasd_discipline *dasd_diag_discipline_pointer;
|
struct dasd_discipline *dasd_diag_discipline_pointer;
|
||||||
|
void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
|
||||||
|
|
||||||
MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
|
MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
|
||||||
MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
|
MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
|
||||||
|
@ -51,7 +52,6 @@ static int dasd_alloc_queue(struct dasd_device * device);
|
||||||
static void dasd_setup_queue(struct dasd_device * device);
|
static void dasd_setup_queue(struct dasd_device * device);
|
||||||
static void dasd_free_queue(struct dasd_device * device);
|
static void dasd_free_queue(struct dasd_device * device);
|
||||||
static void dasd_flush_request_queue(struct dasd_device *);
|
static void dasd_flush_request_queue(struct dasd_device *);
|
||||||
static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
|
|
||||||
static int dasd_flush_ccw_queue(struct dasd_device *, int);
|
static int dasd_flush_ccw_queue(struct dasd_device *, int);
|
||||||
static void dasd_tasklet(struct dasd_device *);
|
static void dasd_tasklet(struct dasd_device *);
|
||||||
static void do_kick_device(struct work_struct *);
|
static void do_kick_device(struct work_struct *);
|
||||||
|
@ -483,7 +483,7 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF;
|
||||||
/*
|
/*
|
||||||
* Add profiling information for cqr before execution.
|
* Add profiling information for cqr before execution.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static void
|
||||||
dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
|
dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
|
||||||
struct request *req)
|
struct request *req)
|
||||||
{
|
{
|
||||||
|
@ -505,7 +505,7 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
|
||||||
/*
|
/*
|
||||||
* Add profiling information for cqr after execution.
|
* Add profiling information for cqr after execution.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static void
|
||||||
dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
|
dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
|
||||||
struct request *req)
|
struct request *req)
|
||||||
{
|
{
|
||||||
|
@ -1022,8 +1022,6 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
||||||
irb->scsw.cstat == 0 &&
|
irb->scsw.cstat == 0 &&
|
||||||
!irb->esw.esw0.erw.cons)
|
!irb->esw.esw0.erw.cons)
|
||||||
era = dasd_era_none;
|
era = dasd_era_none;
|
||||||
else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags))
|
|
||||||
era = dasd_era_fatal; /* don't recover this request */
|
|
||||||
else if (irb->esw.esw0.erw.cons)
|
else if (irb->esw.esw0.erw.cons)
|
||||||
era = device->discipline->examine_error(cqr, irb);
|
era = device->discipline->examine_error(cqr, irb);
|
||||||
else
|
else
|
||||||
|
@ -1104,7 +1102,7 @@ __dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr)
|
||||||
/*
|
/*
|
||||||
* Process ccw request queue.
|
* Process ccw request queue.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static void
|
||||||
__dasd_process_ccw_queue(struct dasd_device * device,
|
__dasd_process_ccw_queue(struct dasd_device * device,
|
||||||
struct list_head *final_queue)
|
struct list_head *final_queue)
|
||||||
{
|
{
|
||||||
|
@ -1127,7 +1125,9 @@ restart:
|
||||||
cqr->status = DASD_CQR_FAILED;
|
cqr->status = DASD_CQR_FAILED;
|
||||||
cqr->stopclk = get_clock();
|
cqr->stopclk = get_clock();
|
||||||
} else {
|
} else {
|
||||||
if (cqr->irb.esw.esw0.erw.cons) {
|
if (cqr->irb.esw.esw0.erw.cons &&
|
||||||
|
test_bit(DASD_CQR_FLAGS_USE_ERP,
|
||||||
|
&cqr->flags)) {
|
||||||
erp_fn = device->discipline->
|
erp_fn = device->discipline->
|
||||||
erp_action(cqr);
|
erp_action(cqr);
|
||||||
erp_fn(cqr);
|
erp_fn(cqr);
|
||||||
|
@ -1181,7 +1181,7 @@ dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
|
||||||
/*
|
/*
|
||||||
* Fetch requests from the block device queue.
|
* Fetch requests from the block device queue.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static void
|
||||||
__dasd_process_blk_queue(struct dasd_device * device)
|
__dasd_process_blk_queue(struct dasd_device * device)
|
||||||
{
|
{
|
||||||
request_queue_t *queue;
|
request_queue_t *queue;
|
||||||
|
@ -1232,6 +1232,19 @@ __dasd_process_blk_queue(struct dasd_device * device)
|
||||||
if (IS_ERR(cqr)) {
|
if (IS_ERR(cqr)) {
|
||||||
if (PTR_ERR(cqr) == -ENOMEM)
|
if (PTR_ERR(cqr) == -ENOMEM)
|
||||||
break; /* terminate request queue loop */
|
break; /* terminate request queue loop */
|
||||||
|
if (PTR_ERR(cqr) == -EAGAIN) {
|
||||||
|
/*
|
||||||
|
* The current request cannot be build right
|
||||||
|
* now, we have to try later. If this request
|
||||||
|
* is the head-of-queue we stop the device
|
||||||
|
* for 1/2 second.
|
||||||
|
*/
|
||||||
|
if (!list_empty(&device->ccw_queue))
|
||||||
|
break;
|
||||||
|
device->stopped |= DASD_STOPPED_PENDING;
|
||||||
|
dasd_set_timer(device, HZ/2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
DBF_DEV_EVENT(DBF_ERR, device,
|
DBF_DEV_EVENT(DBF_ERR, device,
|
||||||
"CCW creation failed (rc=%ld) "
|
"CCW creation failed (rc=%ld) "
|
||||||
"on request %p",
|
"on request %p",
|
||||||
|
@ -1254,7 +1267,7 @@ __dasd_process_blk_queue(struct dasd_device * device)
|
||||||
* Take a look at the first request on the ccw queue and check
|
* Take a look at the first request on the ccw queue and check
|
||||||
* if it reached its expire time. If so, terminate the IO.
|
* if it reached its expire time. If so, terminate the IO.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static void
|
||||||
__dasd_check_expire(struct dasd_device * device)
|
__dasd_check_expire(struct dasd_device * device)
|
||||||
{
|
{
|
||||||
struct dasd_ccw_req *cqr;
|
struct dasd_ccw_req *cqr;
|
||||||
|
@ -1285,7 +1298,7 @@ __dasd_check_expire(struct dasd_device * device)
|
||||||
* Take a look at the first request on the ccw queue and check
|
* Take a look at the first request on the ccw queue and check
|
||||||
* if it needs to be started.
|
* if it needs to be started.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static void
|
||||||
__dasd_start_head(struct dasd_device * device)
|
__dasd_start_head(struct dasd_device * device)
|
||||||
{
|
{
|
||||||
struct dasd_ccw_req *cqr;
|
struct dasd_ccw_req *cqr;
|
||||||
|
|
|
@ -170,7 +170,6 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
|
||||||
/* log the erp chain if fatal error occurred */
|
/* log the erp chain if fatal error occurred */
|
||||||
if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
|
if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
|
||||||
dasd_log_sense(cqr, irb);
|
dasd_log_sense(cqr, irb);
|
||||||
dasd_log_ccw(cqr, 0, irb->scsw.cpa);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return era;
|
return era;
|
||||||
|
@ -2640,7 +2639,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
|
||||||
|
|
||||||
struct dasd_ccw_req *erp = NULL;
|
struct dasd_ccw_req *erp = NULL;
|
||||||
struct dasd_device *device = cqr->device;
|
struct dasd_device *device = cqr->device;
|
||||||
__u32 cpa = cqr->irb.scsw.cpa;
|
|
||||||
struct dasd_ccw_req *temp_erp = NULL;
|
struct dasd_ccw_req *temp_erp = NULL;
|
||||||
|
|
||||||
if (device->features & DASD_FEATURE_ERPLOG) {
|
if (device->features & DASD_FEATURE_ERPLOG) {
|
||||||
|
@ -2706,9 +2704,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (erp->status == DASD_CQR_FAILED)
|
|
||||||
dasd_log_ccw(erp, 1, cpa);
|
|
||||||
|
|
||||||
/* enqueue added ERP request */
|
/* enqueue added ERP request */
|
||||||
if (erp->status == DASD_CQR_FILLED) {
|
if (erp->status == DASD_CQR_FILLED) {
|
||||||
erp->status = DASD_CQR_QUEUED;
|
erp->status = DASD_CQR_QUEUED;
|
||||||
|
|
|
@ -136,7 +136,7 @@ __setup ("dasd=", dasd_call_setup);
|
||||||
/*
|
/*
|
||||||
* Read a device busid/devno from a string.
|
* Read a device busid/devno from a string.
|
||||||
*/
|
*/
|
||||||
static inline int
|
static int
|
||||||
dasd_busid(char **str, int *id0, int *id1, int *devno)
|
dasd_busid(char **str, int *id0, int *id1, int *devno)
|
||||||
{
|
{
|
||||||
int val, old_style;
|
int val, old_style;
|
||||||
|
@ -182,7 +182,7 @@ dasd_busid(char **str, int *id0, int *id1, int *devno)
|
||||||
* only one: "ro" for read-only devices. The default feature set
|
* only one: "ro" for read-only devices. The default feature set
|
||||||
* is empty (value 0).
|
* is empty (value 0).
|
||||||
*/
|
*/
|
||||||
static inline int
|
static int
|
||||||
dasd_feature_list(char *str, char **endp)
|
dasd_feature_list(char *str, char **endp)
|
||||||
{
|
{
|
||||||
int features, len, rc;
|
int features, len, rc;
|
||||||
|
@ -341,7 +341,7 @@ dasd_parse_range( char *parsestring ) {
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline char *
|
static char *
|
||||||
dasd_parse_next_element( char *parsestring ) {
|
dasd_parse_next_element( char *parsestring ) {
|
||||||
char * residual_str;
|
char * residual_str;
|
||||||
residual_str = dasd_parse_keyword(parsestring);
|
residual_str = dasd_parse_keyword(parsestring);
|
||||||
|
|
|
@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");
|
||||||
#define DIAG_MAX_RETRIES 32
|
#define DIAG_MAX_RETRIES 32
|
||||||
#define DIAG_TIMEOUT 50 * HZ
|
#define DIAG_TIMEOUT 50 * HZ
|
||||||
|
|
||||||
struct dasd_discipline dasd_diag_discipline;
|
static struct dasd_discipline dasd_diag_discipline;
|
||||||
|
|
||||||
struct dasd_diag_private {
|
struct dasd_diag_private {
|
||||||
struct dasd_diag_characteristics rdc_data;
|
struct dasd_diag_characteristics rdc_data;
|
||||||
|
@ -90,7 +90,7 @@ static inline int dia250(void *iob, int cmd)
|
||||||
* block offset. On success, return zero and set end_block to contain the
|
* block offset. On success, return zero and set end_block to contain the
|
||||||
* number of blocks on the device minus the specified offset. Return non-zero
|
* number of blocks on the device minus the specified offset. Return non-zero
|
||||||
* otherwise. */
|
* otherwise. */
|
||||||
static __inline__ int
|
static inline int
|
||||||
mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
|
mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
|
||||||
blocknum_t offset, blocknum_t *end_block)
|
blocknum_t offset, blocknum_t *end_block)
|
||||||
{
|
{
|
||||||
|
@ -117,7 +117,7 @@ mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
|
||||||
|
|
||||||
/* Remove block I/O environment for device. Return zero on success, non-zero
|
/* Remove block I/O environment for device. Return zero on success, non-zero
|
||||||
* otherwise. */
|
* otherwise. */
|
||||||
static __inline__ int
|
static inline int
|
||||||
mdsk_term_io(struct dasd_device * device)
|
mdsk_term_io(struct dasd_device * device)
|
||||||
{
|
{
|
||||||
struct dasd_diag_private *private;
|
struct dasd_diag_private *private;
|
||||||
|
@ -576,7 +576,7 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
|
||||||
"dump sense not available for DIAG data");
|
"dump sense not available for DIAG data");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dasd_discipline dasd_diag_discipline = {
|
static struct dasd_discipline dasd_diag_discipline = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "DIAG",
|
.name = "DIAG",
|
||||||
.ebcname = "DIAG",
|
.ebcname = "DIAG",
|
||||||
|
|
|
@ -134,44 +134,7 @@ ceil_quot(unsigned int d1, unsigned int d2)
|
||||||
return (d1 + (d2 - 1)) / d2;
|
return (d1 + (d2 - 1)) / d2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static unsigned int
|
||||||
bytes_per_record(struct dasd_eckd_characteristics *rdc, int kl, int dl)
|
|
||||||
{
|
|
||||||
unsigned int fl1, fl2, int1, int2;
|
|
||||||
int bpr;
|
|
||||||
|
|
||||||
switch (rdc->formula) {
|
|
||||||
case 0x01:
|
|
||||||
fl1 = round_up_multiple(ECKD_F2(rdc) + dl, ECKD_F1(rdc));
|
|
||||||
fl2 = round_up_multiple(kl ? ECKD_F2(rdc) + kl : 0,
|
|
||||||
ECKD_F1(rdc));
|
|
||||||
bpr = fl1 + fl2;
|
|
||||||
break;
|
|
||||||
case 0x02:
|
|
||||||
int1 = ceil_quot(dl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
|
|
||||||
int2 = ceil_quot(kl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
|
|
||||||
fl1 = round_up_multiple(ECKD_F1(rdc) * ECKD_F2(rdc) + dl +
|
|
||||||
ECKD_F6(rdc) + ECKD_F4(rdc) * int1,
|
|
||||||
ECKD_F1(rdc));
|
|
||||||
fl2 = round_up_multiple(ECKD_F1(rdc) * ECKD_F3(rdc) + kl +
|
|
||||||
ECKD_F6(rdc) + ECKD_F4(rdc) * int2,
|
|
||||||
ECKD_F1(rdc));
|
|
||||||
bpr = fl1 + fl2;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
bpr = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return bpr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int
|
|
||||||
bytes_per_track(struct dasd_eckd_characteristics *rdc)
|
|
||||||
{
|
|
||||||
return *(unsigned int *) (rdc->byte_per_track) >> 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int
|
|
||||||
recs_per_track(struct dasd_eckd_characteristics * rdc,
|
recs_per_track(struct dasd_eckd_characteristics * rdc,
|
||||||
unsigned int kl, unsigned int dl)
|
unsigned int kl, unsigned int dl)
|
||||||
{
|
{
|
||||||
|
@ -204,37 +167,39 @@ recs_per_track(struct dasd_eckd_characteristics * rdc,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static int
|
||||||
check_XRC (struct ccw1 *de_ccw,
|
check_XRC (struct ccw1 *de_ccw,
|
||||||
struct DE_eckd_data *data,
|
struct DE_eckd_data *data,
|
||||||
struct dasd_device *device)
|
struct dasd_device *device)
|
||||||
{
|
{
|
||||||
struct dasd_eckd_private *private;
|
struct dasd_eckd_private *private;
|
||||||
|
int rc;
|
||||||
|
|
||||||
private = (struct dasd_eckd_private *) device->private;
|
private = (struct dasd_eckd_private *) device->private;
|
||||||
|
if (!private->rdc_data.facilities.XRC_supported)
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* switch on System Time Stamp - needed for XRC Support */
|
/* switch on System Time Stamp - needed for XRC Support */
|
||||||
if (private->rdc_data.facilities.XRC_supported) {
|
data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
|
||||||
|
data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
|
||||||
|
|
||||||
data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
|
rc = get_sync_clock(&data->ep_sys_time);
|
||||||
data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
|
/* Ignore return code if sync clock is switched off. */
|
||||||
|
if (rc == -ENOSYS || rc == -EACCES)
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
data->ep_sys_time = get_clock ();
|
de_ccw->count = sizeof (struct DE_eckd_data);
|
||||||
|
de_ccw->flags |= CCW_FLAG_SLI;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
de_ccw->count = sizeof (struct DE_eckd_data);
|
static int
|
||||||
de_ccw->flags |= CCW_FLAG_SLI;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
} /* end check_XRC */
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
|
define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
|
||||||
int totrk, int cmd, struct dasd_device * device)
|
int totrk, int cmd, struct dasd_device * device)
|
||||||
{
|
{
|
||||||
struct dasd_eckd_private *private;
|
struct dasd_eckd_private *private;
|
||||||
struct ch_t geo, beg, end;
|
struct ch_t geo, beg, end;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
private = (struct dasd_eckd_private *) device->private;
|
private = (struct dasd_eckd_private *) device->private;
|
||||||
|
|
||||||
|
@ -263,12 +228,12 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
|
||||||
case DASD_ECKD_CCW_WRITE_KD_MT:
|
case DASD_ECKD_CCW_WRITE_KD_MT:
|
||||||
data->mask.perm = 0x02;
|
data->mask.perm = 0x02;
|
||||||
data->attributes.operation = private->attrib.operation;
|
data->attributes.operation = private->attrib.operation;
|
||||||
check_XRC (ccw, data, device);
|
rc = check_XRC (ccw, data, device);
|
||||||
break;
|
break;
|
||||||
case DASD_ECKD_CCW_WRITE_CKD:
|
case DASD_ECKD_CCW_WRITE_CKD:
|
||||||
case DASD_ECKD_CCW_WRITE_CKD_MT:
|
case DASD_ECKD_CCW_WRITE_CKD_MT:
|
||||||
data->attributes.operation = DASD_BYPASS_CACHE;
|
data->attributes.operation = DASD_BYPASS_CACHE;
|
||||||
check_XRC (ccw, data, device);
|
rc = check_XRC (ccw, data, device);
|
||||||
break;
|
break;
|
||||||
case DASD_ECKD_CCW_ERASE:
|
case DASD_ECKD_CCW_ERASE:
|
||||||
case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
|
case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
|
||||||
|
@ -276,7 +241,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
|
||||||
data->mask.perm = 0x3;
|
data->mask.perm = 0x3;
|
||||||
data->mask.auth = 0x1;
|
data->mask.auth = 0x1;
|
||||||
data->attributes.operation = DASD_BYPASS_CACHE;
|
data->attributes.operation = DASD_BYPASS_CACHE;
|
||||||
check_XRC (ccw, data, device);
|
rc = check_XRC (ccw, data, device);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd);
|
DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd);
|
||||||
|
@ -312,9 +277,10 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
|
||||||
data->beg_ext.head = beg.head;
|
data->beg_ext.head = beg.head;
|
||||||
data->end_ext.cyl = end.cyl;
|
data->end_ext.cyl = end.cyl;
|
||||||
data->end_ext.head = end.head;
|
data->end_ext.head = end.head;
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static void
|
||||||
locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
|
locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
|
||||||
int rec_on_trk, int no_rec, int cmd,
|
int rec_on_trk, int no_rec, int cmd,
|
||||||
struct dasd_device * device, int reclen)
|
struct dasd_device * device, int reclen)
|
||||||
|
@ -548,7 +514,7 @@ dasd_eckd_read_conf(struct dasd_device *device)
|
||||||
/*
|
/*
|
||||||
* Build CP for Perform Subsystem Function - SSC.
|
* Build CP for Perform Subsystem Function - SSC.
|
||||||
*/
|
*/
|
||||||
struct dasd_ccw_req *
|
static struct dasd_ccw_req *
|
||||||
dasd_eckd_build_psf_ssc(struct dasd_device *device)
|
dasd_eckd_build_psf_ssc(struct dasd_device *device)
|
||||||
{
|
{
|
||||||
struct dasd_ccw_req *cqr;
|
struct dasd_ccw_req *cqr;
|
||||||
|
@ -1200,7 +1166,12 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
|
||||||
return cqr;
|
return cqr;
|
||||||
ccw = cqr->cpaddr;
|
ccw = cqr->cpaddr;
|
||||||
/* First ccw is define extent. */
|
/* First ccw is define extent. */
|
||||||
define_extent(ccw++, cqr->data, first_trk, last_trk, cmd, device);
|
if (define_extent(ccw++, cqr->data, first_trk,
|
||||||
|
last_trk, cmd, device) == -EAGAIN) {
|
||||||
|
/* Clock not in sync and XRC is enabled. Try again later. */
|
||||||
|
dasd_sfree_request(cqr, device);
|
||||||
|
return ERR_PTR(-EAGAIN);
|
||||||
|
}
|
||||||
/* Build locate_record+read/write/ccws. */
|
/* Build locate_record+read/write/ccws. */
|
||||||
idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
|
idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
|
||||||
LO_data = (struct LO_eckd_data *) (idaws + cidaw);
|
LO_data = (struct LO_eckd_data *) (idaws + cidaw);
|
||||||
|
@ -1380,7 +1351,7 @@ dasd_eckd_release(struct dasd_device *device)
|
||||||
cqr->device = device;
|
cqr->device = device;
|
||||||
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
|
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
|
||||||
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
|
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
|
||||||
cqr->retries = 0;
|
cqr->retries = 2; /* set retry counter to enable basic ERP */
|
||||||
cqr->expires = 2 * HZ;
|
cqr->expires = 2 * HZ;
|
||||||
cqr->buildclk = get_clock();
|
cqr->buildclk = get_clock();
|
||||||
cqr->status = DASD_CQR_FILLED;
|
cqr->status = DASD_CQR_FILLED;
|
||||||
|
@ -1420,7 +1391,7 @@ dasd_eckd_reserve(struct dasd_device *device)
|
||||||
cqr->device = device;
|
cqr->device = device;
|
||||||
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
|
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
|
||||||
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
|
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
|
||||||
cqr->retries = 0;
|
cqr->retries = 2; /* set retry counter to enable basic ERP */
|
||||||
cqr->expires = 2 * HZ;
|
cqr->expires = 2 * HZ;
|
||||||
cqr->buildclk = get_clock();
|
cqr->buildclk = get_clock();
|
||||||
cqr->status = DASD_CQR_FILLED;
|
cqr->status = DASD_CQR_FILLED;
|
||||||
|
@ -1459,7 +1430,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
|
||||||
cqr->device = device;
|
cqr->device = device;
|
||||||
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
|
clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
|
||||||
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
|
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
|
||||||
cqr->retries = 0;
|
cqr->retries = 2; /* set retry counter to enable basic ERP */
|
||||||
cqr->expires = 2 * HZ;
|
cqr->expires = 2 * HZ;
|
||||||
cqr->buildclk = get_clock();
|
cqr->buildclk = get_clock();
|
||||||
cqr->status = DASD_CQR_FILLED;
|
cqr->status = DASD_CQR_FILLED;
|
||||||
|
@ -1609,7 +1580,7 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
|
||||||
* Dump the range of CCWs into 'page' buffer
|
* Dump the range of CCWs into 'page' buffer
|
||||||
* and return number of printed chars.
|
* and return number of printed chars.
|
||||||
*/
|
*/
|
||||||
static inline int
|
static int
|
||||||
dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
|
dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
|
||||||
{
|
{
|
||||||
int len, count;
|
int len, count;
|
||||||
|
|
|
@ -658,18 +658,24 @@ static struct file_operations dasd_eer_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct miscdevice dasd_eer_dev = {
|
static struct miscdevice *dasd_eer_dev = NULL;
|
||||||
.minor = MISC_DYNAMIC_MINOR,
|
|
||||||
.name = "dasd_eer",
|
|
||||||
.fops = &dasd_eer_fops,
|
|
||||||
};
|
|
||||||
|
|
||||||
int __init dasd_eer_init(void)
|
int __init dasd_eer_init(void)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = misc_register(&dasd_eer_dev);
|
dasd_eer_dev = kzalloc(sizeof(*dasd_eer_dev), GFP_KERNEL);
|
||||||
|
if (!dasd_eer_dev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dasd_eer_dev->minor = MISC_DYNAMIC_MINOR;
|
||||||
|
dasd_eer_dev->name = "dasd_eer";
|
||||||
|
dasd_eer_dev->fops = &dasd_eer_fops;
|
||||||
|
|
||||||
|
rc = misc_register(dasd_eer_dev);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
kfree(dasd_eer_dev);
|
||||||
|
dasd_eer_dev = NULL;
|
||||||
MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
|
MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
|
||||||
"register misc device");
|
"register misc device");
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -680,5 +686,9 @@ int __init dasd_eer_init(void)
|
||||||
|
|
||||||
void dasd_eer_exit(void)
|
void dasd_eer_exit(void)
|
||||||
{
|
{
|
||||||
WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
|
if (dasd_eer_dev) {
|
||||||
|
WARN_ON(misc_deregister(dasd_eer_dev) != 0);
|
||||||
|
kfree(dasd_eer_dev);
|
||||||
|
dasd_eer_dev = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,25 +152,6 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
|
||||||
|
|
||||||
} /* end default_erp_postaction */
|
} /* end default_erp_postaction */
|
||||||
|
|
||||||
/*
|
|
||||||
* Print the hex dump of the memory used by a request. This includes
|
|
||||||
* all error recovery ccws that have been chained in from of the
|
|
||||||
* real request.
|
|
||||||
*/
|
|
||||||
static inline void
|
|
||||||
hex_dump_memory(struct dasd_device *device, void *data, int len)
|
|
||||||
{
|
|
||||||
int *pint;
|
|
||||||
|
|
||||||
pint = (int *) data;
|
|
||||||
while (len > 0) {
|
|
||||||
DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x",
|
|
||||||
pint, pint[0], pint[1], pint[2], pint[3]);
|
|
||||||
pint += 4;
|
|
||||||
len -= 16;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
|
dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
|
||||||
{
|
{
|
||||||
|
@ -182,69 +163,8 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
|
||||||
device->discipline->dump_sense(device, cqr, irb);
|
device->discipline->dump_sense(device, cqr, irb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa)
|
|
||||||
{
|
|
||||||
struct dasd_device *device;
|
|
||||||
struct dasd_ccw_req *lcqr;
|
|
||||||
struct ccw1 *ccw;
|
|
||||||
int cplength;
|
|
||||||
|
|
||||||
device = cqr->device;
|
|
||||||
/* log the channel program */
|
|
||||||
for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) {
|
|
||||||
DEV_MESSAGE(KERN_ERR, device,
|
|
||||||
"(%s) ERP chain report for req: %p",
|
|
||||||
caller == 0 ? "EXAMINE" : "ACTION", lcqr);
|
|
||||||
hex_dump_memory(device, lcqr, sizeof(struct dasd_ccw_req));
|
|
||||||
|
|
||||||
cplength = 1;
|
|
||||||
ccw = lcqr->cpaddr;
|
|
||||||
while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC))
|
|
||||||
cplength++;
|
|
||||||
|
|
||||||
if (cplength > 40) { /* log only parts of the CP */
|
|
||||||
DEV_MESSAGE(KERN_ERR, device, "%s",
|
|
||||||
"Start of channel program:");
|
|
||||||
hex_dump_memory(device, lcqr->cpaddr,
|
|
||||||
40*sizeof(struct ccw1));
|
|
||||||
|
|
||||||
DEV_MESSAGE(KERN_ERR, device, "%s",
|
|
||||||
"End of channel program:");
|
|
||||||
hex_dump_memory(device, lcqr->cpaddr + cplength - 10,
|
|
||||||
10*sizeof(struct ccw1));
|
|
||||||
} else { /* log the whole CP */
|
|
||||||
DEV_MESSAGE(KERN_ERR, device, "%s",
|
|
||||||
"Channel program (complete):");
|
|
||||||
hex_dump_memory(device, lcqr->cpaddr,
|
|
||||||
cplength*sizeof(struct ccw1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lcqr != cqr)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Log bytes arround failed CCW but only if we did
|
|
||||||
* not log the whole CP of the CCW is outside the
|
|
||||||
* logged CP.
|
|
||||||
*/
|
|
||||||
if (cplength > 40 ||
|
|
||||||
((addr_t) cpa < (addr_t) lcqr->cpaddr &&
|
|
||||||
(addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) {
|
|
||||||
|
|
||||||
DEV_MESSAGE(KERN_ERR, device,
|
|
||||||
"Failed CCW (%p) (area):",
|
|
||||||
(void *) (long) cpa);
|
|
||||||
hex_dump_memory(device, cqr->cpaddr - 10,
|
|
||||||
20*sizeof(struct ccw1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} /* end log_erp_chain */
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(dasd_default_erp_action);
|
EXPORT_SYMBOL(dasd_default_erp_action);
|
||||||
EXPORT_SYMBOL(dasd_default_erp_postaction);
|
EXPORT_SYMBOL(dasd_default_erp_postaction);
|
||||||
EXPORT_SYMBOL(dasd_alloc_erp_request);
|
EXPORT_SYMBOL(dasd_alloc_erp_request);
|
||||||
EXPORT_SYMBOL(dasd_free_erp_request);
|
EXPORT_SYMBOL(dasd_free_erp_request);
|
||||||
EXPORT_SYMBOL(dasd_log_sense);
|
EXPORT_SYMBOL(dasd_log_sense);
|
||||||
EXPORT_SYMBOL(dasd_log_ccw);
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ static struct ccw_driver dasd_fba_driver = {
|
||||||
.notify = dasd_generic_notify,
|
.notify = dasd_generic_notify,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void
|
static void
|
||||||
define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
|
define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
|
||||||
int blksize, int beg, int nr)
|
int blksize, int beg, int nr)
|
||||||
{
|
{
|
||||||
|
@ -95,7 +95,7 @@ define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
|
||||||
data->ext_end = nr - 1;
|
data->ext_end = nr - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static void
|
||||||
locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
|
locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
|
||||||
int block_nr, int block_ct)
|
int block_nr, int block_ct)
|
||||||
{
|
{
|
||||||
|
|
|
@ -147,7 +147,7 @@ dasd_destroy_partitions(struct dasd_device * device)
|
||||||
*/
|
*/
|
||||||
memset(&bpart, 0, sizeof(struct blkpg_partition));
|
memset(&bpart, 0, sizeof(struct blkpg_partition));
|
||||||
memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
|
memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
|
||||||
barg.data = (void __user *) &bpart;
|
barg.data = (void __force __user *) &bpart;
|
||||||
barg.op = BLKPG_DEL_PARTITION;
|
barg.op = BLKPG_DEL_PARTITION;
|
||||||
for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
|
for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
|
||||||
ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
|
ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
|
||||||
|
|
|
@ -559,7 +559,6 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
|
||||||
struct dasd_device *);
|
struct dasd_device *);
|
||||||
void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
|
void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
|
||||||
void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
|
void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
|
||||||
void dasd_log_ccw(struct dasd_ccw_req *, int, __u32);
|
|
||||||
|
|
||||||
/* externals in dasd_3370_erp.c */
|
/* externals in dasd_3370_erp.c */
|
||||||
dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
|
dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
|
||||||
|
|
|
@ -28,7 +28,7 @@ static struct proc_dir_entry *dasd_proc_root_entry = NULL;
|
||||||
static struct proc_dir_entry *dasd_devices_entry = NULL;
|
static struct proc_dir_entry *dasd_devices_entry = NULL;
|
||||||
static struct proc_dir_entry *dasd_statistics_entry = NULL;
|
static struct proc_dir_entry *dasd_statistics_entry = NULL;
|
||||||
|
|
||||||
static inline char *
|
static char *
|
||||||
dasd_get_user_string(const char __user *user_buf, size_t user_len)
|
dasd_get_user_string(const char __user *user_buf, size_t user_len)
|
||||||
{
|
{
|
||||||
char *buffer;
|
char *buffer;
|
||||||
|
@ -154,7 +154,7 @@ static struct file_operations dasd_devices_file_ops = {
|
||||||
.release = seq_release,
|
.release = seq_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline int
|
static int
|
||||||
dasd_calc_metrics(char *page, char **start, off_t off,
|
dasd_calc_metrics(char *page, char **start, off_t off,
|
||||||
int count, int *eof, int len)
|
int count, int *eof, int len)
|
||||||
{
|
{
|
||||||
|
@ -167,8 +167,8 @@ dasd_calc_metrics(char *page, char **start, off_t off,
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline char *
|
static char *
|
||||||
dasd_statistics_array(char *str, int *array, int shift)
|
dasd_statistics_array(char *str, unsigned int *array, int shift)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
|
@ -102,7 +102,7 @@ dcssblk_release_segment(struct device *dev)
|
||||||
* device needs to be enqueued before the semaphore is
|
* device needs to be enqueued before the semaphore is
|
||||||
* freed.
|
* freed.
|
||||||
*/
|
*/
|
||||||
static inline int
|
static int
|
||||||
dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
|
dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
|
||||||
{
|
{
|
||||||
int minor, found;
|
int minor, found;
|
||||||
|
@ -230,7 +230,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
|
||||||
SEGMENT_SHARED);
|
SEGMENT_SHARED);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
BUG_ON(rc == -EINVAL);
|
BUG_ON(rc == -EINVAL);
|
||||||
if (rc == -EIO || rc == -ENOENT)
|
if (rc != -EAGAIN)
|
||||||
goto removeseg;
|
goto removeseg;
|
||||||
} else {
|
} else {
|
||||||
dev_info->is_shared = 1;
|
dev_info->is_shared = 1;
|
||||||
|
@ -253,7 +253,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
|
||||||
SEGMENT_EXCLUSIVE);
|
SEGMENT_EXCLUSIVE);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
BUG_ON(rc == -EINVAL);
|
BUG_ON(rc == -EINVAL);
|
||||||
if (rc == -EIO || rc == -ENOENT)
|
if (rc != -EAGAIN)
|
||||||
goto removeseg;
|
goto removeseg;
|
||||||
} else {
|
} else {
|
||||||
dev_info->is_shared = 0;
|
dev_info->is_shared = 0;
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
# S/390 character devices
|
# S/390 character devices
|
||||||
#
|
#
|
||||||
|
|
||||||
obj-y += ctrlchar.o keyboard.o defkeymap.o
|
obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
|
||||||
|
sclp_info.o
|
||||||
|
|
||||||
obj-$(CONFIG_TN3270) += raw3270.o
|
obj-$(CONFIG_TN3270) += raw3270.o
|
||||||
obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
|
obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
|
||||||
|
@ -11,7 +12,6 @@ obj-$(CONFIG_TN3270_FS) += fs3270.o
|
||||||
|
|
||||||
obj-$(CONFIG_TN3215) += con3215.o
|
obj-$(CONFIG_TN3215) += con3215.o
|
||||||
|
|
||||||
obj-$(CONFIG_SCLP) += sclp.o sclp_rw.o sclp_quiesce.o
|
|
||||||
obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
|
obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
|
||||||
obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
|
obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
|
||||||
obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
|
obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
|
||||||
|
|
|
@ -1121,7 +1121,7 @@ static const struct tty_operations tty3215_ops = {
|
||||||
* 3215 tty registration code called from tty_init().
|
* 3215 tty registration code called from tty_init().
|
||||||
* Most kernel services (incl. kmalloc) are available at this poimt.
|
* Most kernel services (incl. kmalloc) are available at this poimt.
|
||||||
*/
|
*/
|
||||||
int __init
|
static int __init
|
||||||
tty3215_init(void)
|
tty3215_init(void)
|
||||||
{
|
{
|
||||||
struct tty_driver *driver;
|
struct tty_driver *driver;
|
||||||
|
|
|
@ -69,8 +69,7 @@ static void con3270_update(struct con3270 *);
|
||||||
/*
|
/*
|
||||||
* Setup timeout for a device. On timeout trigger an update.
|
* Setup timeout for a device. On timeout trigger an update.
|
||||||
*/
|
*/
|
||||||
void
|
static void con3270_set_timer(struct con3270 *cp, int expires)
|
||||||
con3270_set_timer(struct con3270 *cp, int expires)
|
|
||||||
{
|
{
|
||||||
if (expires == 0) {
|
if (expires == 0) {
|
||||||
if (timer_pending(&cp->timer))
|
if (timer_pending(&cp->timer))
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/keyboard.h>
|
#include <linux/keyboard.h>
|
||||||
#include <linux/kd.h>
|
#include <linux/kd.h>
|
||||||
|
#include <linux/kbd_kern.h>
|
||||||
|
#include <linux/kbd_diacr.h>
|
||||||
|
|
||||||
u_short plain_map[NR_KEYS] = {
|
u_short plain_map[NR_KEYS] = {
|
||||||
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
|
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "raw3270.h"
|
#include "raw3270.h"
|
||||||
#include "ctrlchar.h"
|
#include "ctrlchar.h"
|
||||||
|
|
||||||
struct raw3270_fn fs3270_fn;
|
static struct raw3270_fn fs3270_fn;
|
||||||
|
|
||||||
struct fs3270 {
|
struct fs3270 {
|
||||||
struct raw3270_view view;
|
struct raw3270_view view;
|
||||||
|
@ -401,7 +401,7 @@ fs3270_release(struct raw3270_view *view)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* View to a 3270 device. Can be console, tty or fullscreen. */
|
/* View to a 3270 device. Can be console, tty or fullscreen. */
|
||||||
struct raw3270_fn fs3270_fn = {
|
static struct raw3270_fn fs3270_fn = {
|
||||||
.activate = fs3270_activate,
|
.activate = fs3270_activate,
|
||||||
.deactivate = fs3270_deactivate,
|
.deactivate = fs3270_deactivate,
|
||||||
.intv = (void *) fs3270_irq,
|
.intv = (void *) fs3270_irq,
|
||||||
|
|
|
@ -148,6 +148,7 @@ kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
/*
|
/*
|
||||||
* Generate ebcdic -> ascii translation table from kbd_data.
|
* Generate ebcdic -> ascii translation table from kbd_data.
|
||||||
*/
|
*/
|
||||||
|
@ -173,6 +174,7 @@ kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have a combining character DIACR here, followed by the character CH.
|
* We have a combining character DIACR here, followed by the character CH.
|
||||||
|
|
|
@ -67,8 +67,8 @@ static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
|
static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
|
||||||
struct monwrite_hdr *monhdr)
|
struct monwrite_hdr *monhdr)
|
||||||
{
|
{
|
||||||
struct mon_buf *entry, *next;
|
struct mon_buf *entry, *next;
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
|
||||||
struct class *class3270;
|
static struct class *class3270;
|
||||||
|
|
||||||
/* The main 3270 data structure. */
|
/* The main 3270 data structure. */
|
||||||
struct raw3270 {
|
struct raw3270 {
|
||||||
|
@ -86,7 +86,7 @@ DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
|
||||||
/*
|
/*
|
||||||
* Encode array for 12 bit 3270 addresses.
|
* Encode array for 12 bit 3270 addresses.
|
||||||
*/
|
*/
|
||||||
unsigned char raw3270_ebcgraf[64] = {
|
static unsigned char raw3270_ebcgraf[64] = {
|
||||||
0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||||
0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||||
0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||||
|
|
|
@ -59,7 +59,8 @@ static volatile enum sclp_init_state_t {
|
||||||
/* Internal state: is a request active at the sclp? */
|
/* Internal state: is a request active at the sclp? */
|
||||||
static volatile enum sclp_running_state_t {
|
static volatile enum sclp_running_state_t {
|
||||||
sclp_running_state_idle,
|
sclp_running_state_idle,
|
||||||
sclp_running_state_running
|
sclp_running_state_running,
|
||||||
|
sclp_running_state_reset_pending
|
||||||
} sclp_running_state = sclp_running_state_idle;
|
} sclp_running_state = sclp_running_state_idle;
|
||||||
|
|
||||||
/* Internal state: is a read request pending? */
|
/* Internal state: is a read request pending? */
|
||||||
|
@ -88,15 +89,15 @@ static volatile enum sclp_mask_state_t {
|
||||||
|
|
||||||
/* Timeout intervals in seconds.*/
|
/* Timeout intervals in seconds.*/
|
||||||
#define SCLP_BUSY_INTERVAL 10
|
#define SCLP_BUSY_INTERVAL 10
|
||||||
#define SCLP_RETRY_INTERVAL 15
|
#define SCLP_RETRY_INTERVAL 30
|
||||||
|
|
||||||
static void sclp_process_queue(void);
|
static void sclp_process_queue(void);
|
||||||
static int sclp_init_mask(int calculate);
|
static int sclp_init_mask(int calculate);
|
||||||
static int sclp_init(void);
|
static int sclp_init(void);
|
||||||
|
|
||||||
/* Perform service call. Return 0 on success, non-zero otherwise. */
|
/* Perform service call. Return 0 on success, non-zero otherwise. */
|
||||||
static int
|
int
|
||||||
service_call(sclp_cmdw_t command, void *sccb)
|
sclp_service_call(sclp_cmdw_t command, void *sccb)
|
||||||
{
|
{
|
||||||
int cc;
|
int cc;
|
||||||
|
|
||||||
|
@ -113,19 +114,17 @@ service_call(sclp_cmdw_t command, void *sccb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Request timeout handler. Restart the request queue. If DATA is non-zero,
|
static inline void __sclp_make_read_req(void);
|
||||||
* force restart of running request. */
|
|
||||||
static void
|
|
||||||
sclp_request_timeout(unsigned long data)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
if (data) {
|
static void
|
||||||
spin_lock_irqsave(&sclp_lock, flags);
|
__sclp_queue_read_req(void)
|
||||||
sclp_running_state = sclp_running_state_idle;
|
{
|
||||||
spin_unlock_irqrestore(&sclp_lock, flags);
|
if (sclp_reading_state == sclp_reading_state_idle) {
|
||||||
|
sclp_reading_state = sclp_reading_state_reading;
|
||||||
|
__sclp_make_read_req();
|
||||||
|
/* Add request to head of queue */
|
||||||
|
list_add(&sclp_read_req.list, &sclp_req_queue);
|
||||||
}
|
}
|
||||||
sclp_process_queue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set up request retry timer. Called while sclp_lock is locked. */
|
/* Set up request retry timer. Called while sclp_lock is locked. */
|
||||||
|
@ -140,6 +139,29 @@ __sclp_set_request_timer(unsigned long time, void (*function)(unsigned long),
|
||||||
add_timer(&sclp_request_timer);
|
add_timer(&sclp_request_timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Request timeout handler. Restart the request queue. If DATA is non-zero,
|
||||||
|
* force restart of running request. */
|
||||||
|
static void
|
||||||
|
sclp_request_timeout(unsigned long data)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&sclp_lock, flags);
|
||||||
|
if (data) {
|
||||||
|
if (sclp_running_state == sclp_running_state_running) {
|
||||||
|
/* Break running state and queue NOP read event request
|
||||||
|
* to get a defined interface state. */
|
||||||
|
__sclp_queue_read_req();
|
||||||
|
sclp_running_state = sclp_running_state_idle;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
__sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
|
||||||
|
sclp_request_timeout, 0);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&sclp_lock, flags);
|
||||||
|
sclp_process_queue();
|
||||||
|
}
|
||||||
|
|
||||||
/* Try to start a request. Return zero if the request was successfully
|
/* Try to start a request. Return zero if the request was successfully
|
||||||
* started or if it will be started at a later time. Return non-zero otherwise.
|
* started or if it will be started at a later time. Return non-zero otherwise.
|
||||||
* Called while sclp_lock is locked. */
|
* Called while sclp_lock is locked. */
|
||||||
|
@ -151,7 +173,7 @@ __sclp_start_request(struct sclp_req *req)
|
||||||
if (sclp_running_state != sclp_running_state_idle)
|
if (sclp_running_state != sclp_running_state_idle)
|
||||||
return 0;
|
return 0;
|
||||||
del_timer(&sclp_request_timer);
|
del_timer(&sclp_request_timer);
|
||||||
rc = service_call(req->command, req->sccb);
|
rc = sclp_service_call(req->command, req->sccb);
|
||||||
req->start_count++;
|
req->start_count++;
|
||||||
|
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
|
@ -191,7 +213,15 @@ sclp_process_queue(void)
|
||||||
rc = __sclp_start_request(req);
|
rc = __sclp_start_request(req);
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
break;
|
break;
|
||||||
/* Request failed. */
|
/* Request failed */
|
||||||
|
if (req->start_count > 1) {
|
||||||
|
/* Cannot abort already submitted request - could still
|
||||||
|
* be active at the SCLP */
|
||||||
|
__sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
|
||||||
|
sclp_request_timeout, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Post-processing for aborted request */
|
||||||
list_del(&req->list);
|
list_del(&req->list);
|
||||||
if (req->callback) {
|
if (req->callback) {
|
||||||
spin_unlock_irqrestore(&sclp_lock, flags);
|
spin_unlock_irqrestore(&sclp_lock, flags);
|
||||||
|
@ -221,7 +251,8 @@ sclp_add_request(struct sclp_req *req)
|
||||||
list_add_tail(&req->list, &sclp_req_queue);
|
list_add_tail(&req->list, &sclp_req_queue);
|
||||||
rc = 0;
|
rc = 0;
|
||||||
/* Start if request is first in list */
|
/* Start if request is first in list */
|
||||||
if (req->list.prev == &sclp_req_queue) {
|
if (sclp_running_state == sclp_running_state_idle &&
|
||||||
|
req->list.prev == &sclp_req_queue) {
|
||||||
rc = __sclp_start_request(req);
|
rc = __sclp_start_request(req);
|
||||||
if (rc)
|
if (rc)
|
||||||
list_del(&req->list);
|
list_del(&req->list);
|
||||||
|
@ -294,7 +325,7 @@ __sclp_make_read_req(void)
|
||||||
sccb = (struct sccb_header *) sclp_read_sccb;
|
sccb = (struct sccb_header *) sclp_read_sccb;
|
||||||
clear_page(sccb);
|
clear_page(sccb);
|
||||||
memset(&sclp_read_req, 0, sizeof(struct sclp_req));
|
memset(&sclp_read_req, 0, sizeof(struct sclp_req));
|
||||||
sclp_read_req.command = SCLP_CMDW_READDATA;
|
sclp_read_req.command = SCLP_CMDW_READ_EVENT_DATA;
|
||||||
sclp_read_req.status = SCLP_REQ_QUEUED;
|
sclp_read_req.status = SCLP_REQ_QUEUED;
|
||||||
sclp_read_req.start_count = 0;
|
sclp_read_req.start_count = 0;
|
||||||
sclp_read_req.callback = sclp_read_cb;
|
sclp_read_req.callback = sclp_read_cb;
|
||||||
|
@ -334,6 +365,8 @@ sclp_interrupt_handler(__u16 code)
|
||||||
finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
|
finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
|
||||||
evbuf_pending = S390_lowcore.ext_params & 0x3;
|
evbuf_pending = S390_lowcore.ext_params & 0x3;
|
||||||
if (finished_sccb) {
|
if (finished_sccb) {
|
||||||
|
del_timer(&sclp_request_timer);
|
||||||
|
sclp_running_state = sclp_running_state_reset_pending;
|
||||||
req = __sclp_find_req(finished_sccb);
|
req = __sclp_find_req(finished_sccb);
|
||||||
if (req) {
|
if (req) {
|
||||||
/* Request post-processing */
|
/* Request post-processing */
|
||||||
|
@ -348,13 +381,8 @@ sclp_interrupt_handler(__u16 code)
|
||||||
sclp_running_state = sclp_running_state_idle;
|
sclp_running_state = sclp_running_state_idle;
|
||||||
}
|
}
|
||||||
if (evbuf_pending && sclp_receive_mask != 0 &&
|
if (evbuf_pending && sclp_receive_mask != 0 &&
|
||||||
sclp_reading_state == sclp_reading_state_idle &&
|
sclp_activation_state == sclp_activation_state_active)
|
||||||
sclp_activation_state == sclp_activation_state_active ) {
|
__sclp_queue_read_req();
|
||||||
sclp_reading_state = sclp_reading_state_reading;
|
|
||||||
__sclp_make_read_req();
|
|
||||||
/* Add request to head of queue */
|
|
||||||
list_add(&sclp_read_req.list, &sclp_req_queue);
|
|
||||||
}
|
|
||||||
spin_unlock(&sclp_lock);
|
spin_unlock(&sclp_lock);
|
||||||
sclp_process_queue();
|
sclp_process_queue();
|
||||||
}
|
}
|
||||||
|
@ -374,6 +402,7 @@ sclp_sync_wait(void)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned long cr0, cr0_sync;
|
unsigned long cr0, cr0_sync;
|
||||||
u64 timeout;
|
u64 timeout;
|
||||||
|
int irq_context;
|
||||||
|
|
||||||
/* We'll be disabling timer interrupts, so we need a custom timeout
|
/* We'll be disabling timer interrupts, so we need a custom timeout
|
||||||
* mechanism */
|
* mechanism */
|
||||||
|
@ -386,7 +415,9 @@ sclp_sync_wait(void)
|
||||||
}
|
}
|
||||||
local_irq_save(flags);
|
local_irq_save(flags);
|
||||||
/* Prevent bottom half from executing once we force interrupts open */
|
/* Prevent bottom half from executing once we force interrupts open */
|
||||||
local_bh_disable();
|
irq_context = in_interrupt();
|
||||||
|
if (!irq_context)
|
||||||
|
local_bh_disable();
|
||||||
/* Enable service-signal interruption, disable timer interrupts */
|
/* Enable service-signal interruption, disable timer interrupts */
|
||||||
trace_hardirqs_on();
|
trace_hardirqs_on();
|
||||||
__ctl_store(cr0, 0, 0);
|
__ctl_store(cr0, 0, 0);
|
||||||
|
@ -402,19 +433,19 @@ sclp_sync_wait(void)
|
||||||
get_clock() > timeout &&
|
get_clock() > timeout &&
|
||||||
del_timer(&sclp_request_timer))
|
del_timer(&sclp_request_timer))
|
||||||
sclp_request_timer.function(sclp_request_timer.data);
|
sclp_request_timer.function(sclp_request_timer.data);
|
||||||
barrier();
|
|
||||||
cpu_relax();
|
cpu_relax();
|
||||||
}
|
}
|
||||||
local_irq_disable();
|
local_irq_disable();
|
||||||
__ctl_load(cr0, 0, 0);
|
__ctl_load(cr0, 0, 0);
|
||||||
_local_bh_enable();
|
if (!irq_context)
|
||||||
|
_local_bh_enable();
|
||||||
local_irq_restore(flags);
|
local_irq_restore(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(sclp_sync_wait);
|
EXPORT_SYMBOL(sclp_sync_wait);
|
||||||
|
|
||||||
/* Dispatch changes in send and receive mask to registered listeners. */
|
/* Dispatch changes in send and receive mask to registered listeners. */
|
||||||
static inline void
|
static void
|
||||||
sclp_dispatch_state_change(void)
|
sclp_dispatch_state_change(void)
|
||||||
{
|
{
|
||||||
struct list_head *l;
|
struct list_head *l;
|
||||||
|
@ -597,7 +628,7 @@ __sclp_make_init_req(u32 receive_mask, u32 send_mask)
|
||||||
sccb = (struct init_sccb *) sclp_init_sccb;
|
sccb = (struct init_sccb *) sclp_init_sccb;
|
||||||
clear_page(sccb);
|
clear_page(sccb);
|
||||||
memset(&sclp_init_req, 0, sizeof(struct sclp_req));
|
memset(&sclp_init_req, 0, sizeof(struct sclp_req));
|
||||||
sclp_init_req.command = SCLP_CMDW_WRITEMASK;
|
sclp_init_req.command = SCLP_CMDW_WRITE_EVENT_MASK;
|
||||||
sclp_init_req.status = SCLP_REQ_FILLED;
|
sclp_init_req.status = SCLP_REQ_FILLED;
|
||||||
sclp_init_req.start_count = 0;
|
sclp_init_req.start_count = 0;
|
||||||
sclp_init_req.callback = NULL;
|
sclp_init_req.callback = NULL;
|
||||||
|
@ -800,7 +831,7 @@ sclp_check_interface(void)
|
||||||
for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) {
|
for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) {
|
||||||
__sclp_make_init_req(0, 0);
|
__sclp_make_init_req(0, 0);
|
||||||
sccb = (struct init_sccb *) sclp_init_req.sccb;
|
sccb = (struct init_sccb *) sclp_init_req.sccb;
|
||||||
rc = service_call(sclp_init_req.command, sccb);
|
rc = sclp_service_call(sclp_init_req.command, sccb);
|
||||||
if (rc == -EIO)
|
if (rc == -EIO)
|
||||||
break;
|
break;
|
||||||
sclp_init_req.status = SCLP_REQ_RUNNING;
|
sclp_init_req.status = SCLP_REQ_RUNNING;
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <asm/sclp.h>
|
||||||
#include <asm/ebcdic.h>
|
#include <asm/ebcdic.h>
|
||||||
|
|
||||||
/* maximum number of pages concerning our own memory management */
|
/* maximum number of pages concerning our own memory management */
|
||||||
|
@ -49,9 +49,11 @@
|
||||||
|
|
||||||
typedef unsigned int sclp_cmdw_t;
|
typedef unsigned int sclp_cmdw_t;
|
||||||
|
|
||||||
#define SCLP_CMDW_READDATA 0x00770005
|
#define SCLP_CMDW_READ_EVENT_DATA 0x00770005
|
||||||
#define SCLP_CMDW_WRITEDATA 0x00760005
|
#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005
|
||||||
#define SCLP_CMDW_WRITEMASK 0x00780005
|
#define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005
|
||||||
|
#define SCLP_CMDW_READ_SCP_INFO 0x00020001
|
||||||
|
#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
|
||||||
|
|
||||||
#define GDS_ID_MDSMU 0x1310
|
#define GDS_ID_MDSMU 0x1310
|
||||||
#define GDS_ID_MDSRouteInfo 0x1311
|
#define GDS_ID_MDSRouteInfo 0x1311
|
||||||
|
@ -66,13 +68,6 @@ typedef unsigned int sclp_cmdw_t;
|
||||||
|
|
||||||
typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */
|
typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */
|
||||||
|
|
||||||
struct sccb_header {
|
|
||||||
u16 length;
|
|
||||||
u8 function_code;
|
|
||||||
u8 control_mask[3];
|
|
||||||
u16 response_code;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
struct gds_subvector {
|
struct gds_subvector {
|
||||||
u8 length;
|
u8 length;
|
||||||
u8 key;
|
u8 key;
|
||||||
|
@ -131,6 +126,7 @@ void sclp_unregister(struct sclp_register *reg);
|
||||||
int sclp_remove_processed(struct sccb_header *sccb);
|
int sclp_remove_processed(struct sccb_header *sccb);
|
||||||
int sclp_deactivate(void);
|
int sclp_deactivate(void);
|
||||||
int sclp_reactivate(void);
|
int sclp_reactivate(void);
|
||||||
|
int sclp_service_call(sclp_cmdw_t command, void *sccb);
|
||||||
|
|
||||||
/* useful inlines */
|
/* useful inlines */
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
|
||||||
} while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
|
} while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static void
|
||||||
sclp_conbuf_emit(void)
|
sclp_conbuf_emit(void)
|
||||||
{
|
{
|
||||||
struct sclp_buffer* buffer;
|
struct sclp_buffer* buffer;
|
||||||
|
|
|
@ -169,7 +169,7 @@ cpi_prepare_req(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* prepare request data structure presented to SCLP driver */
|
/* prepare request data structure presented to SCLP driver */
|
||||||
req->command = SCLP_CMDW_WRITEDATA;
|
req->command = SCLP_CMDW_WRITE_EVENT_DATA;
|
||||||
req->sccb = sccb;
|
req->sccb = sccb;
|
||||||
req->status = SCLP_REQ_FILLED;
|
req->status = SCLP_REQ_FILLED;
|
||||||
req->callback = cpi_callback;
|
req->callback = cpi_callback;
|
||||||
|
|
57
drivers/s390/char/sclp_info.c
Normal file
57
drivers/s390/char/sclp_info.c
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/*
|
||||||
|
* drivers/s390/char/sclp_info.c
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2007
|
||||||
|
* Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <asm/sclp.h>
|
||||||
|
#include "sclp.h"
|
||||||
|
|
||||||
|
struct sclp_readinfo_sccb s390_readinfo_sccb;
|
||||||
|
|
||||||
|
void __init sclp_readinfo_early(void)
|
||||||
|
{
|
||||||
|
sclp_cmdw_t command;
|
||||||
|
struct sccb_header *sccb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
__ctl_set_bit(0, 9); /* enable service signal subclass mask */
|
||||||
|
|
||||||
|
sccb = &s390_readinfo_sccb.header;
|
||||||
|
command = SCLP_CMDW_READ_SCP_INFO_FORCED;
|
||||||
|
while (1) {
|
||||||
|
u16 response;
|
||||||
|
|
||||||
|
memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb));
|
||||||
|
sccb->length = sizeof(s390_readinfo_sccb);
|
||||||
|
sccb->control_mask[2] = 0x80;
|
||||||
|
|
||||||
|
ret = sclp_service_call(command, &s390_readinfo_sccb);
|
||||||
|
|
||||||
|
if (ret == -EIO)
|
||||||
|
goto out;
|
||||||
|
if (ret == -EBUSY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
__load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
|
||||||
|
PSW_MASK_WAIT | PSW_DEFAULT_KEY);
|
||||||
|
local_irq_disable();
|
||||||
|
barrier();
|
||||||
|
|
||||||
|
response = sccb->response_code;
|
||||||
|
|
||||||
|
if (response == 0x10)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO)
|
||||||
|
break;
|
||||||
|
|
||||||
|
command = SCLP_CMDW_READ_SCP_INFO;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
__ctl_clear_bit(0, 9); /* disable service signal subclass mask */
|
||||||
|
}
|
|
@ -460,7 +460,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
|
||||||
sccb->msg_buf.header.type = EvTyp_PMsgCmd;
|
sccb->msg_buf.header.type = EvTyp_PMsgCmd;
|
||||||
else
|
else
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
buffer->request.command = SCLP_CMDW_WRITEDATA;
|
buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
|
||||||
buffer->request.status = SCLP_REQ_FILLED;
|
buffer->request.status = SCLP_REQ_FILLED;
|
||||||
buffer->request.callback = sclp_writedata_callback;
|
buffer->request.callback = sclp_writedata_callback;
|
||||||
buffer->request.callback_data = buffer;
|
buffer->request.callback_data = buffer;
|
||||||
|
|
|
@ -721,7 +721,7 @@ static const struct tty_operations sclp_ops = {
|
||||||
.ioctl = sclp_tty_ioctl,
|
.ioctl = sclp_tty_ioctl,
|
||||||
};
|
};
|
||||||
|
|
||||||
int __init
|
static int __init
|
||||||
sclp_tty_init(void)
|
sclp_tty_init(void)
|
||||||
{
|
{
|
||||||
struct tty_driver *driver;
|
struct tty_driver *driver;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue