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:
Linus Torvalds 2007-02-06 14:45:32 -08:00
commit 02aedd69e2
168 changed files with 5591 additions and 2242 deletions

View File

@ -480,7 +480,7 @@ r2 argument 0 / return value 0 call-clobbered
r3 argument 1 / return value 1 (if long long) call-clobbered
r4 argument 2 call-clobbered
r5 argument 3 call-clobbered
r6 argument 5 saved
r6 argument 4 saved
r7 pointer-to arguments 5 to ... saved
r8 this & that saved
r9 this & that saved

View File

@ -2791,7 +2791,7 @@ M: schwidefsky@de.ibm.com
P: Heiko Carstens
M: heiko.carstens@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/
S: Supported
@ -2799,7 +2799,7 @@ S390 NETWORK DRIVERS
P: Frank Pavlic
M: fpavlic@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/
S: Supported
@ -2807,7 +2807,7 @@ S390 ZFCP DRIVER
P: Swen Schillig
M: swen@vnet.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/
S: Supported

View File

@ -34,10 +34,6 @@ config GENERIC_HWEIGHT
bool
default y
config GENERIC_CALIBRATE_DELAY
bool
default y
config GENERIC_TIME
def_bool y
@ -134,6 +130,31 @@ config AUDIT_ARCH
bool
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"
choice

View File

@ -81,7 +81,7 @@ static struct ctl_table appldata_dir_table[] = {
/*
* 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 DEFINE_SPINLOCK(appldata_timer_lock);

View File

@ -36,7 +36,7 @@
* book:
* http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
*/
struct appldata_mem_data {
static struct appldata_mem_data {
u64 timestamp;
u32 sync_count_1; /* after VM collected the record data, */
u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the

View File

@ -34,7 +34,7 @@
* book:
* http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
*/
struct appldata_net_sum_data {
static struct appldata_net_sum_data {
u64 timestamp;
u32 sync_count_1; /* after VM collected the record data, */
u32 sync_count_2; /* sync_count_1 and sync_count_2 should be the

60
arch/s390/crypto/Kconfig Normal file
View 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.

View File

@ -6,5 +6,4 @@ obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_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_AES_S390) += aes_s390.o
obj-$(CONFIG_CRYPTO_TEST) += crypt_s390_query.o
obj-$(CONFIG_S390_PRNG) += prng.o

View File

@ -4,7 +4,7 @@
* s390 implementation of the AES Cipher Algorithm.
*
* s390 Version:
* Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation
* Copyright IBM Corp. 2005,2007
* Author(s): Jan Glauber (jang@de.ibm.com)
*
* Derived from "crypto/aes.c"
@ -27,9 +27,11 @@
/* data block size for all key lengths */
#define AES_BLOCK_SIZE 16
int has_aes_128 = 0;
int has_aes_192 = 0;
int has_aes_256 = 0;
#define AES_KEYLEN_128 1
#define AES_KEYLEN_192 2
#define AES_KEYLEN_256 4
static char keylen_flag = 0;
struct s390_aes_ctx {
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) {
case 16:
if (!has_aes_128)
if (!(keylen_flag & AES_KEYLEN_128))
goto fail;
break;
case 24:
if (!has_aes_192)
if (!(keylen_flag & AES_KEYLEN_192))
goto fail;
break;
case 32:
if (!has_aes_256)
if (!(keylen_flag & AES_KEYLEN_256))
goto fail;
break;
default:
/* invalid key length */
goto fail;
break;
}
@ -322,34 +323,32 @@ static int __init aes_init(void)
int ret;
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))
has_aes_192 = 1;
keylen_flag |= AES_KEYLEN_192;
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)
return -ENOSYS;
if (!keylen_flag)
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);
if (ret != 0) {
printk(KERN_INFO "crypt_s390: aes-s390 couldn't be loaded.\n");
if (ret)
goto aes_err;
}
ret = crypto_register_alg(&ecb_aes_alg);
if (ret != 0) {
printk(KERN_INFO
"crypt_s390: ecb-aes-s390 couldn't be loaded.\n");
if (ret)
goto ecb_aes_err;
}
ret = crypto_register_alg(&cbc_aes_alg);
if (ret != 0) {
printk(KERN_INFO
"crypt_s390: cbc-aes-s390 couldn't be loaded.\n");
if (ret)
goto cbc_aes_err;
}
out:
return ret;

View File

@ -3,8 +3,9 @@
*
* Support for s390 cryptographic instructions.
*
* Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
* Copyright IBM Corp. 2003,2007
* Author(s): Thomas Spatzier
* Jan Glauber (jan.glauber@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
@ -32,7 +33,8 @@ enum crypt_s390_operations {
CRYPT_S390_KMAC = 0x0500
};
/* function codes for KM (CIPHER MESSAGE) instruction
/*
* function codes for KM (CIPHER MESSAGE) instruction
* 0x80 is the decipher modifier bit
*/
enum crypt_s390_km_func {
@ -51,7 +53,8 @@ enum crypt_s390_km_func {
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
*/
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_256_ENCRYPT = CRYPT_S390_KMC | 0x14,
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
*/
enum crypt_s390_kimd_func {
@ -79,7 +84,8 @@ enum crypt_s390_kimd_func {
KIMD_SHA_256 = CRYPT_S390_KIMD | 2,
};
/* function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
/*
* function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
* instruction
*/
enum crypt_s390_klmd_func {
@ -88,7 +94,8 @@ enum crypt_s390_klmd_func {
KLMD_SHA_256 = CRYPT_S390_KLMD | 2,
};
/* function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
/*
* function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
* instruction
*/
enum crypt_s390_kmac_func {
@ -98,198 +105,196 @@ enum crypt_s390_kmac_func {
KMAC_TDEA_192 = CRYPT_S390_KMAC | 3
};
/* status word for s390 crypto instructions' QUERY functions */
struct crypt_s390_query_status {
u64 high;
u64 low;
};
/*
/**
* crypt_s390_km:
* @func: the function code passed to KM; see crypt_s390_km_func
* @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.
* @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
* @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
*
* Returns -1 for failure, 0 for the query func, number of processed
* bytes for encryption/decryption funcs
*/
static inline int
crypt_s390_km(long func, void* param, u8* dest, const u8* src, long src_len)
static inline int crypt_s390_km(long func, void *param,
u8 *dest, const u8 *src, long src_len)
{
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
register void* __param asm("1") = param;
register const u8* __src asm("2") = src;
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;
register u8 *__dest asm("4") = dest;
int ret;
asm volatile(
"0: .insn rre,0xb92e0000,%3,%1 \n" /* KM 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)
" la %0,0\n"
"2:\n"
EX_TABLE(0b,2b) 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 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");
: "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;
}
/**
* Tests if a specific crypto function is implemented on the machine.
* @param func: the function code of the specific function; 0 if op in general
* @return 1 if func available; 0 if func or op in general not available
* crypt_s390_kmc:
* @func: the function code passed to KM; see crypt_s390_kmc_func
* @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
crypt_s390_func_available(int func)
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;
struct crypt_s390_query_status status = {
.high = 0,
.low = 0
};
switch (func & CRYPT_S390_OP_MASK){
asm volatile(
"0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC 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), "+a" (__dest)
: "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_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;
@ -306,21 +311,13 @@ crypt_s390_func_available(int func)
ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
break;
default:
ret = 0;
return ret;
return 0;
}
if (ret >= 0){
if (ret < 0)
return 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;
func &= 0x7f; /* mask modifier bit */
return (status[func >> 3] & (0x80 >> (func & 7))) != 0;
}
#endif // _CRYPTO_ARCH_S390_CRYPT_S390_H
#endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */

View File

@ -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");

View File

@ -10,8 +10,9 @@
* scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL.
*
* s390 Version:
* Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
* Copyright IBM Corp. 2003
* Author(s): Thomas Spatzier
* Jan Glauber (jan.glauber@de.ibm.com)
*
* Derived from "crypto/des.c"
* Copyright (c) 1992 Dana L. How.
@ -30,6 +31,7 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/crypto.h>
#include "crypto_des.h"
#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o))

View File

@ -3,9 +3,9 @@
*
* s390 implementation of the DES Cipher Algorithm.
*
* Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
*
* Copyright IBM Corp. 2003,2007
* Author(s): Thomas Spatzier
* Jan Glauber (jan.glauber@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
@ -557,7 +557,7 @@ static int init(void)
if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
!crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
!crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
return -ENOSYS;
return -EOPNOTSUPP;
ret = crypto_register_alg(&des_alg);
if (ret)

213
arch/s390/crypto/prng.c Normal file
View 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);

View File

@ -8,8 +8,9 @@
* implementation written by Steve Reid.
*
* s390 Version:
* Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
* Copyright IBM Corp. 2003,2007
* Author(s): Thomas Spatzier
* Jan Glauber (jan.glauber@de.ibm.com)
*
* Derived from "crypto/sha1.c"
* Copyright (c) Alan Smithee.
@ -43,16 +44,14 @@ struct crypt_s390_sha1_ctx {
static void sha1_init(struct crypto_tfm *tfm)
{
struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm);
static const u32 initstate[5] = {
0x67452301,
0xEFCDAB89,
0x98BADCFE,
0x10325476,
0xC3D2E1F0
};
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
ctx->state[4] = 0xC3D2E1F0;
ctx->count = 0;
memcpy(ctx->state, &initstate, sizeof(initstate));
ctx->buf_len = 0;
}
@ -63,11 +62,11 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
long imd_len;
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) {
//complete full block and hash
/* complete full block and hash */
memcpy(sctx->buffer + sctx->buf_len, data,
SHA1_BLOCK_SIZE - sctx->buf_len);
crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer,
@ -77,35 +76,34 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
sctx->buf_len = 0;
}
//rest of data contains full blocks?
/* rest of data contains full blocks? */
imd_len = len & ~0x3ful;
if (imd_len){
if (imd_len) {
crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len);
data += imd_len;
len -= imd_len;
}
//anything left? store in buffer
if (len){
/* anything left? store in buffer */
if (len) {
memcpy(sctx->buffer + sctx->buf_len , data, len);
sctx->buf_len += len;
}
}
static void
pad_message(struct crypt_s390_sha1_ctx* sctx)
static void pad_message(struct crypt_s390_sha1_ctx* sctx)
{
int index;
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;
//start pad with 1
/* start pad with 1 */
sctx->buffer[index] = 0x80;
//pad with zeros
/* pad with zeros */
index++;
memset(sctx->buffer + index, 0x00, sctx->buf_len - index);
//append length
/* append length */
memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count,
sizeof sctx->count);
}
@ -115,18 +113,18 @@ static void sha1_final(struct crypto_tfm *tfm, u8 *out)
{
struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
//must perform manual padding
/* must perform manual padding */
pad_message(sctx);
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);
/* Wipe context */
/* wipe context */
memset(sctx, 0, sizeof *sctx);
}
static struct crypto_alg alg = {
.cra_name = "sha1",
.cra_driver_name = "sha1-s390",
.cra_driver_name= "sha1-s390",
.cra_priority = CRYPT_S390_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_DIGEST,
.cra_blocksize = SHA1_BLOCK_SIZE,
@ -140,22 +138,15 @@ static struct crypto_alg alg = {
.dia_final = sha1_final } }
};
static int
init(void)
static int __init init(void)
{
int ret = -ENOSYS;
if (!crypt_s390_func_available(KIMD_SHA_1))
return -EOPNOTSUPP;
if (crypt_s390_func_available(KIMD_SHA_1)){
ret = crypto_register_alg(&alg);
if (ret == 0){
printk(KERN_INFO "crypt_s390: sha1_s390 loaded.\n");
}
}
return ret;
return crypto_register_alg(&alg);
}
static void __exit
fini(void)
static void __exit fini(void)
{
crypto_unregister_alg(&alg);
}

View File

@ -4,7 +4,7 @@
* s390 implementation of the SHA256 Secure Hash Algorithm.
*
* s390 Version:
* Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation
* Copyright IBM Corp. 2005,2007
* Author(s): Jan Glauber (jang@de.ibm.com)
*
* Derived from "crypto/sha256.c"
@ -143,15 +143,10 @@ static struct crypto_alg alg = {
static int init(void)
{
int ret;
if (!crypt_s390_func_available(KIMD_SHA_256))
return -ENOSYS;
return -EOPNOTSUPP;
ret = crypto_register_alg(&alg);
if (ret != 0)
printk(KERN_INFO "crypt_s390: sha256_s390 couldn't be loaded.");
return ret;
return crypto_register_alg(&alg);
}
static void __exit fini(void)

View File

@ -108,6 +108,8 @@ CONFIG_DEFAULT_MIGRATION_COST=1000000
CONFIG_COMPAT=y
CONFIG_SYSVIPC_COMPAT=y
CONFIG_AUDIT_ARCH=y
CONFIG_S390_SWITCH_AMODE=y
CONFIG_S390_EXEC_PROTECT=y
#
# Code generation options
@ -431,7 +433,6 @@ CONFIG_TN3270_CONSOLE=y
CONFIG_TN3215=y
CONFIG_TN3215_CONSOLE=y
CONFIG_CCW_CONSOLE=y
CONFIG_SCLP=y
CONFIG_SCLP_TTY=y
CONFIG_SCLP_CONSOLE=y
CONFIG_SCLP_VT220_TTY=y
@ -724,9 +725,7 @@ CONFIG_CRYPTO_MANAGER=y
# CONFIG_CRYPTO_MD4 is not set
# CONFIG_CRYPTO_MD5 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_S390 is not set
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
@ -735,12 +734,10 @@ CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
# CONFIG_CRYPTO_LRW is not set
# CONFIG_CRYPTO_DES is not set
# CONFIG_CRYPTO_DES_S390 is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
# CONFIG_CRYPTO_SERPENT is not set
# CONFIG_CRYPTO_AES is not set
# CONFIG_CRYPTO_AES_S390 is not set
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
# CONFIG_CRYPTO_TEA is not set
@ -755,6 +752,11 @@ CONFIG_CRYPTO_CBC=y
#
# 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

View File

@ -4,4 +4,4 @@
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

View File

@ -27,4 +27,13 @@ extern struct dentry *hypfs_create_str(struct super_block *sb,
struct dentry *dir, const char *name,
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_ */

View File

@ -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
View 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;
}

View File

@ -19,7 +19,6 @@
#include <linux/module.h>
#include <asm/ebcdic.h>
#include "hypfs.h"
#include "hypfs_diag.h"
#define HYPFS_MAGIC 0x687970 /* ASCII 'hyp' */
#define TMP_SIZE 64 /* size of temporary buffers */
@ -192,6 +191,9 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
goto out;
}
hypfs_delete_tree(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) {
printk(KERN_ERR "hypfs: Update failed\n");
@ -289,6 +291,9 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
rc = -ENOMEM;
goto err_alloc;
}
if (MACHINE_IS_VM)
rc = hypfs_vm_create_files(sb, root_dentry);
else
rc = hypfs_diag_create_files(sb, root_dentry);
if (rc)
goto err_tree;
@ -462,12 +467,16 @@ static int __init hypfs_init(void)
{
int rc;
if (MACHINE_IS_VM)
if (MACHINE_IS_VM) {
if (hypfs_vm_init())
/* no diag 2fc, just exit */
return -ENODATA;
} else {
if (hypfs_diag_init()) {
rc = -ENODATA;
goto fail_diag;
}
}
kset_set_kset_s(&s390_subsys, hypervisor_subsys);
rc = subsystem_register(&s390_subsys);
if (rc)
@ -480,6 +489,7 @@ static int __init hypfs_init(void)
fail_filesystem:
subsystem_unregister(&s390_subsys);
fail_sysfs:
if (!MACHINE_IS_VM)
hypfs_diag_exit();
fail_diag:
printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
@ -488,6 +498,7 @@ fail_diag:
static void __exit hypfs_exit(void)
{
if (!MACHINE_IS_VM)
hypfs_diag_exit();
unregister_filesystem(&hypfs_type);
subsystem_unregister(&s390_subsys);

View File

@ -4,9 +4,9 @@
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 \
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),reipl64.o,reipl.o)

150
arch/s390/kernel/base.S Normal file
View 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 */

View File

@ -192,7 +192,7 @@ MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>");
#undef cputime_to_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)
{
value->tv_usec = cputime % 1000000;

View File

@ -12,10 +12,9 @@
#include <linux/personality.h>
#include <linux/sched.h>
struct exec_domain s390_exec_domain;
static struct exec_domain s390_exec_domain;
static int __init
s390_init (void)
static int __init s390_init (void)
{
s390_exec_domain.name = "Linux/s390";
s390_exec_domain.handler = NULL;

View File

@ -69,6 +69,12 @@
#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. */
@ -416,7 +422,7 @@ asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
mm_segment_t old_fs = get_fs ();
set_fs (KERNEL_DS);
ret = sys_sysinfo((struct sysinfo __user *) &s);
ret = sys_sysinfo((struct sysinfo __force __user *) &s);
set_fs (old_fs);
err = put_user (s.uptime, &info->uptime);
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 ();
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);
if (put_compat_timespec(&t, interval))
return -EFAULT;
@ -472,8 +479,8 @@ asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
}
set_fs (KERNEL_DS);
ret = sys_rt_sigprocmask(how,
set ? (sigset_t __user *) &s : NULL,
oset ? (sigset_t __user *) &s : NULL,
set ? (sigset_t __force __user *) &s : NULL,
oset ? (sigset_t __force __user *) &s : NULL,
sigsetsize);
set_fs (old_fs);
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();
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);
if (!ret) {
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))
return -EFAULT;
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);
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);
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);
if (offset && put_user(of, offset))
@ -703,7 +710,8 @@ asmlinkage long sys32_sendfile64(int out_fd, int in_fd,
set_fs(KERNEL_DS);
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);
if (offset && put_user(lof, offset))

View File

@ -115,37 +115,6 @@ typedef struct
__u32 addr;
} _psw_t32 __attribute__ ((aligned(8)));
#define PSW32_MASK_PER 0x40000000UL
#define PSW32_MASK_DAT 0x04000000UL
#define PSW32_MASK_IO 0x02000000UL
#define PSW32_MASK_EXT 0x01000000UL
#define PSW32_MASK_KEY 0x00F00000UL
#define PSW32_MASK_MCHECK 0x00040000UL
#define PSW32_MASK_WAIT 0x00020000UL
#define PSW32_MASK_PSTATE 0x00010000UL
#define PSW32_MASK_ASC 0x0000C000UL
#define PSW32_MASK_CC 0x00003000UL
#define PSW32_MASK_PM 0x00000f00UL
#define PSW32_ADDR_AMODE31 0x80000000UL
#define PSW32_ADDR_INSN 0x7FFFFFFFUL
#define PSW32_BASE_BITS 0x00080000UL
#define PSW32_ASC_PRIMARY 0x00000000UL
#define PSW32_ASC_ACCREG 0x00004000UL
#define PSW32_ASC_SECONDARY 0x00008000UL
#define PSW32_ASC_HOME 0x0000C000UL
#define PSW32_USER_BITS (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \
PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \
PSW32_MASK_PSTATE)
#define PSW32_MASK_MERGE(CURRENT,NEW) \
(((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \
((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM)))
typedef struct
{
_psw_t32 psw;

View File

@ -275,8 +275,8 @@ sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss,
}
set_fs (KERNEL_DS);
ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL),
(stack_t __user *) (uoss ? &koss : NULL),
ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL),
(stack_t __force __user *) (uoss ? &koss : NULL),
regs->gprs[15]);
set_fs (old_fs);
@ -298,7 +298,7 @@ static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
_s390_regs_common32 regs32;
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));
regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
for (i = 0; i < NUM_GPRS; i++)
@ -401,7 +401,7 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
goto badframe;
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);
return regs->gprs[2];

View File

@ -16,6 +16,7 @@
#include <asm/ebcdic.h>
#include <asm/cpcmd.h>
#include <asm/system.h>
#include <asm/io.h>
static DEFINE_SPINLOCK(cpcmd_lock);
static char cpcmd_buf[241];
@ -88,13 +89,8 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
int len;
unsigned long flags;
if ((rlen == 0) || (response == NULL)
|| !((unsigned long)response >> 31)) {
spin_lock_irqsave(&cpcmd_lock, flags);
len = __cpcmd(cmd, response, rlen, response_code);
spin_unlock_irqrestore(&cpcmd_lock, flags);
}
else {
if ((virt_to_phys(response) != (unsigned long) response) ||
(((unsigned long)response + rlen) >> 31)) {
lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
if (!lowbuf) {
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);
memcpy(response, lowbuf, rlen);
kfree(lowbuf);
} else {
spin_lock_irqsave(&cpcmd_lock, flags);
len = __cpcmd(cmd, response, rlen, response_code);
spin_unlock_irqrestore(&cpcmd_lock, flags);
}
return len;
}

View File

@ -9,6 +9,7 @@
#include <linux/threads.h>
#include <linux/kexec.h>
#include <linux/reboot.h>
void machine_crash_shutdown(struct pt_regs *regs)
{

View File

@ -120,7 +120,7 @@ struct debug_view debug_hex_ascii_view = {
NULL
};
struct debug_view debug_level_view = {
static struct debug_view debug_level_view = {
"level",
&debug_prolog_level_fn,
NULL,
@ -129,7 +129,7 @@ struct debug_view debug_level_view = {
NULL
};
struct debug_view debug_pages_view = {
static struct debug_view debug_pages_view = {
"pages",
&debug_prolog_pages_fn,
NULL,
@ -138,7 +138,7 @@ struct debug_view debug_pages_view = {
NULL
};
struct debug_view debug_flush_view = {
static struct debug_view debug_flush_view = {
"flush",
NULL,
NULL,
@ -156,14 +156,14 @@ struct debug_view debug_sprintf_view = {
NULL
};
/* used by dump analysis tools to determine version of debug feature */
unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
/* static globals */
static debug_info_t *debug_area_first = NULL;
static debug_info_t *debug_area_last = NULL;
DECLARE_MUTEX(debug_lock);
static DECLARE_MUTEX(debug_lock);
static int initialized;
@ -905,7 +905,7 @@ static struct ctl_table s390dbf_dir_table[] = {
{ .ctl_name = 0 }
};
struct ctl_table_header *s390dbf_sysctl_header;
static struct ctl_table_header *s390dbf_sysctl_header;
void
debug_stop_all(void)
@ -1300,8 +1300,7 @@ out:
* flushes debug areas
*/
void
debug_flush(debug_info_t* id, int area)
static void debug_flush(debug_info_t* id, int area)
{
unsigned long flags;
int i,j;
@ -1511,8 +1510,7 @@ out:
/*
* clean up module
*/
void
__exit debug_exit(void)
static void __exit debug_exit(void)
{
debugfs_remove(debug_debugfs_root_entry);
unregister_sysctl_table(s390dbf_sysctl_header);

306
arch/s390/kernel/early.c Normal file
View 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();
}

View File

@ -11,6 +11,7 @@
#include <linux/module.h>
#include <asm/types.h>
#include <asm/ebcdic.h>
/*
* ASCII (IBM PC 437) -> EBCDIC 037

View File

@ -51,175 +51,14 @@ startup_continue:
st %r15,__LC_KERNEL_STACK # set end of kernel stack
ahi %r15,-96
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
l %r14,.Lipl_save_parameters-.LPG1(%r13)
#
# 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
#
# 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
#
# 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
#
@ -295,7 +134,6 @@ startup_continue:
.long 0 # cr15: linkage stack operations
.Lduct: .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
.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
@ -306,7 +144,9 @@ startup_continue:
.Lbss_bgn: .long __bss_start
.Lbss_end: .long _end
.Lparmaddr: .long PARMAREA
.Lsccbaddr: .long .Lsccb
.Linittu: .long init_thread_union
.Lstartup_init:
.long startup_init
.globl ipl_schib
ipl_schib:
@ -322,26 +162,6 @@ ipl_devno:
.word 0
.org 0x12000
.globl s390_readinfo_sccb
s390_readinfo_sccb:
.Lsccb:
.hword 0x1000 # length, one page
.byte 0x00,0x00,0x00
.byte 0x80 # variable response bit set
.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
.org 0x100000
#endif

View File

@ -58,182 +58,14 @@ startup_continue:
stg %r15,__LC_KERNEL_STACK # set end of kernel stack
aghi %r15,-160
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
brasl %r14,ipl_save_parameters
#
# clear bss memory
# 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
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
brasl %r14,startup_init
# set program check new psw mask
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
#
# 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
#
@ -336,25 +168,6 @@ ipl_devno:
.word 0
.org 0x12000
.globl s390_readinfo_sccb
s390_readinfo_sccb:
.Lsccb:
.hword 0x1000 # length, one page
.byte 0x00,0x00,0x00
.byte 0x80 # variable response bit set
.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
.org 0x100000

View File

@ -20,26 +20,27 @@
#include <asm/cio.h>
#include <asm/ebcdic.h>
#include <asm/reset.h>
#include <asm/sclp.h>
#define IPL_PARM_BLOCK_VERSION 0
#define LOADPARM_LEN 8
extern char s390_readinfo_sccb[];
#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010)
#define SCCB_LOADPARM (&s390_readinfo_sccb[24])
#define SCCB_FLAG (s390_readinfo_sccb[91])
#define SCCB_VALID (s390_readinfo_sccb.header.response_code == 0x10)
#define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm)
#define SCCB_FLAG (s390_readinfo_sccb.flags)
enum ipl_type {
IPL_TYPE_NONE = 1,
IPL_TYPE_UNKNOWN = 2,
IPL_TYPE_CCW = 4,
IPL_TYPE_FCP = 8,
IPL_TYPE_NSS = 16,
};
#define IPL_NONE_STR "none"
#define IPL_UNKNOWN_STR "unknown"
#define IPL_CCW_STR "ccw"
#define IPL_FCP_STR "fcp"
#define IPL_NSS_STR "nss"
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;
case IPL_TYPE_FCP:
return IPL_FCP_STR;
case IPL_TYPE_NSS:
return IPL_NSS_STR;
case IPL_TYPE_UNKNOWN:
default:
return IPL_UNKNOWN_STR;
@ -64,6 +67,7 @@ enum ipl_method {
IPL_METHOD_FCP_RO_DIAG,
IPL_METHOD_FCP_RW_DIAG,
IPL_METHOD_FCP_RO_VM,
IPL_METHOD_NSS,
};
enum shutdown_action {
@ -114,11 +118,14 @@ enum diag308_rc {
static int diag308_set_works = 0;
static int reipl_capabilities = IPL_TYPE_UNKNOWN;
static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
static enum ipl_method reipl_method = IPL_METHOD_NONE;
static struct ipl_parameter_block *reipl_block_fcp;
static struct ipl_parameter_block *reipl_block_ccw;
static char reipl_nss_name[NSS_NAME_SIZE + 1];
static int dump_capabilities = IPL_TYPE_NONE;
static enum ipl_type dump_type = IPL_TYPE_NONE;
static enum ipl_method dump_method = IPL_METHOD_NONE;
@ -173,6 +180,24 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
sys_##_prefix##_##_name##_show, \
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)
{
while (*attrs) {
@ -189,6 +214,8 @@ static enum ipl_type ipl_get_type(void)
{
struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
if (ipl_flags & IPL_NSS_VALID)
return IPL_TYPE_NSS;
if (!(ipl_flags & IPL_DEVNO_VALID))
return IPL_TYPE_UNKNOWN;
if (!(ipl_flags & IPL_PARMBLOCK_VALID))
@ -324,6 +351,20 @@ static struct attribute_group ipl_ccw_attr_group = {
.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 */
static struct attribute *ipl_unknown_attrs[] = {
@ -432,6 +473,21 @@ static struct attribute_group reipl_ccw_attr_group = {
.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 */
static int reipl_set_type(enum ipl_type type)
@ -454,6 +510,9 @@ static int reipl_set_type(enum ipl_type type)
else
reipl_method = IPL_METHOD_FCP_RO_DIAG;
break;
case IPL_TYPE_NSS:
reipl_method = IPL_METHOD_NSS;
break;
default:
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);
else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
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;
}
@ -647,6 +708,10 @@ void do_reipl(void)
case IPL_METHOD_FCP_RO_VM:
__cpcmd("IPL", NULL, 0, NULL);
break;
case IPL_METHOD_NSS:
sprintf(buf, "IPL %s", reipl_nss_name);
__cpcmd(buf, NULL, 0, NULL);
break;
case IPL_METHOD_NONE:
default:
if (MACHINE_IS_VM)
@ -733,6 +798,10 @@ static int __init ipl_init(void)
case IPL_TYPE_FCP:
rc = ipl_register_fcp_files();
break;
case IPL_TYPE_NSS:
rc = sysfs_create_group(&ipl_subsys.kset.kobj,
&ipl_nss_attr_group);
break;
default:
rc = sysfs_create_group(&ipl_subsys.kset.kobj,
&ipl_unknown_attr_group);
@ -755,6 +824,20 @@ static void __init reipl_probe(void)
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)
{
int rc;
@ -835,6 +918,9 @@ static int __init reipl_init(void)
if (rc)
return rc;
rc = reipl_fcp_init();
if (rc)
return rc;
rc = reipl_nss_init();
if (rc)
return rc;
rc = reipl_set_type(ipl_get_type());
@ -993,8 +1079,6 @@ static void do_reset_calls(void)
reset->fn();
}
extern void reset_mcck_handler(void);
extern void reset_pgm_handler(void);
extern __u32 dump_prefix_page;
void s390_reset_system(void)
@ -1016,14 +1100,14 @@ void s390_reset_system(void)
__ctl_clear_bit(0,28);
/* 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 =
PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
PSW_ADDR_AMODE | (unsigned long) s390_base_mcck_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 =
PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler;
PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
do_reset_calls();
}

View File

@ -1,9 +1,9 @@
/*
* arch/s390/kernel/irq.c
*
* S390 version
* Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Copyright IBM Corp. 2004,2007
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Thomas Spatzier (tspat@de.ibm.com)
*
* This file contains interrupt related functions.
*/
@ -14,6 +14,8 @@
#include <linux/interrupt.h>
#include <linux/seq_file.h>
#include <linux/cpu.h>
#include <linux/proc_fs.h>
#include <linux/profile.h>
/*
* show_interrupts is needed by /proc/interrupts.
@ -93,5 +95,12 @@ asmlinkage void do_softirq(void)
local_irq_restore(flags);
}
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);
}

View File

@ -155,15 +155,34 @@ void __kprobes get_instruction_type(struct arch_specific_insn *ainsn)
static int __kprobes swap_instruction(void *aref)
{
struct ins_replace_args *args = aref;
u32 *addr;
u32 instr;
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(
"0: mvc 0(2,%2),0(%3)\n"
" lra %1,0(%1)\n"
"0: stura %2,%1\n"
"1: la %0,0\n"
"2:\n"
EX_TABLE(0b,2b)
: "+d" (err), "=m" (*args->ptr)
: "a" (args->ptr), "a" (&args->new), "m" (args->new));
: "+d" (err)
: "a" (addr), "d" (instr)
: "memory", "cc");
return err;
}
@ -356,7 +375,7 @@ no_kprobe:
* - When the probed function returns, this probe
* causes the handlers to fire
*/
void __kprobes kretprobe_trampoline_holder(void)
void kretprobe_trampoline_holder(void)
{
asm volatile(".global kretprobe_trampoline\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
*/
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 hlist_head *head, empty_rp;

View File

@ -11,6 +11,7 @@
#include <linux/mm.h>
#include <linux/kexec.h>
#include <linux/delay.h>
#include <linux/reboot.h>
#include <asm/cio.h>
#include <asm/setup.h>
#include <asm/pgtable.h>

View File

@ -30,6 +30,7 @@
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/moduleloader.h>
#if 0
#define DEBUGP printk
@ -58,7 +59,7 @@ void module_free(struct module *mod, void *module_region)
table entries. */
}
static inline void
static void
check_rela(Elf_Rela *rela, struct module *me)
{
struct mod_arch_syminfo *info;
@ -181,7 +182,7 @@ apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex,
return -ENOEXEC;
}
static inline int
static int
apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab,
struct module *me)
{

View File

@ -144,7 +144,7 @@ static void default_idle(void)
trace_hardirqs_on();
/* 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);
}
@ -190,7 +190,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
struct pt_regs regs;
memset(&regs, 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.gprs[9] = (unsigned long) fn;
regs.gprs[10] = (unsigned long) arg;

View File

@ -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);
}

View File

@ -86,15 +86,13 @@ FixPerRegisters(struct task_struct *task)
per_info->control_regs.bits.storage_alt_space_ctl = 0;
}
void
set_single_step(struct task_struct *task)
static void set_single_step(struct task_struct *task)
{
task->thread.per_info.single_step = 1;
FixPerRegisters(task);
}
void
clear_single_step(struct task_struct *task)
static void clear_single_step(struct task_struct *task)
{
task->thread.per_info.single_step = 0;
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 &&
#ifdef CONFIG_COMPAT
data != PSW_MASK_MERGE(PSW_USER32_BITS, data) &&
data != PSW_MASK_MERGE(psw_user32_bits, data) &&
#endif
data != PSW_MASK_MERGE(PSW_USER_BITS, data))
data != PSW_MASK_MERGE(psw_user_bits, data))
/* Invalid psw mask. */
return -EINVAL;
#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);
if (copied != sizeof(tmp))
return -EIO;
return put_user(tmp, (unsigned long __user *) data);
return put_user(tmp, (unsigned long __force __user *) data);
case PTRACE_PEEKUSR:
/* 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_POKEUSR_AREA:
if (copy_from_user(&parea, (void __user *) addr,
if (copy_from_user(&parea, (void __force __user *) addr,
sizeof(parea)))
return -EFAULT;
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)
ret = peek_user(child, addr, data);
else {
addr_t tmp;
if (get_user (tmp, (addr_t __user *) data))
addr_t utmp;
if (get_user(utmp,
(addr_t __force __user *) data))
return -EFAULT;
ret = poke_user(child, addr, tmp);
ret = poke_user(child, addr, utmp);
}
if (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) {
/* Fake a 31 bit psw mask. */
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) {
/* Fake a 31 bit psw address. */
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) {
/* 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. */
return -EINVAL;
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) {
/* Build a 64 bit psw address from 31 bit address. */
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);
if (copied != sizeof(tmp))
return -EIO;
return put_user(tmp, (unsigned int __user *) data);
return put_user(tmp, (unsigned int __force __user *) data);
case PTRACE_PEEKUSR:
/* 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_POKEUSR_AREA:
if (copy_from_user(&parea, (void __user *) addr,
if (copy_from_user(&parea, (void __force __user *) addr,
sizeof(parea)))
return -EFAULT;
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)
ret = peek_user_emu31(child, addr, data);
else {
__u32 tmp;
if (get_user (tmp, (__u32 __user *) data))
__u32 utmp;
if (get_user(utmp,
(__u32 __force __user *) data))
return -EFAULT;
ret = poke_user_emu31(child, addr, tmp);
ret = poke_user_emu31(child, addr, utmp);
}
if (ret)
return ret;
@ -595,17 +595,19 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
return 0;
case PTRACE_GETEVENTMSG:
return put_user((__u32) child->ptrace_message,
(unsigned int __user *) data);
(unsigned int __force __user *) data);
case PTRACE_GETSIGINFO:
if (child->last_siginfo == NULL)
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);
case PTRACE_SETSIGINFO:
if (child->last_siginfo == NULL)
return -EINVAL;
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);
}

View File

@ -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 */

View File

@ -125,15 +125,13 @@ void do_extint(struct pt_regs *regs, unsigned short code)
* Make sure that the i/o interrupt did not "overtake"
* the last HZ timer interrupt.
*/
account_ticks();
account_ticks(S390_lowcore.int_clock);
kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
index = ext_hash(code);
for (p = ext_int_hash[index]; p; p = p->next) {
if (likely(p->code == code)) {
if (likely(p->handler))
if (likely(p->code == code))
p->handler(code);
}
}
irq_exit();
set_irq_regs(old_regs);
}

View File

@ -38,6 +38,8 @@
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/pfn.h>
#include <linux/ctype.h>
#include <linux/reboot.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@ -49,6 +51,14 @@
#include <asm/page.h>
#include <asm/ptrace.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.
@ -117,9 +127,9 @@ void __devinit cpu_init (void)
*/
char vmhalt_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;
@ -275,10 +285,6 @@ static void __init conmode_default(void)
}
#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_halt)(void) = machine_halt_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);
#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
setup_lowcore(void)
{
@ -402,19 +486,21 @@ setup_lowcore(void)
lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
lc->restart_psw.addr =
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 =
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->program_new_psw.mask = PSW_KERNEL_BITS;
lc->program_new_psw.mask = psw_kernel_bits;
lc->program_new_psw.addr =
PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
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 =
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->ipl_device = S390_lowcore.ipl_device;
lc->jiffy_timer = -1LL;
@ -439,7 +525,7 @@ setup_lowcore(void)
static void __init
setup_resources(void)
{
struct resource *res;
struct resource *res, *sub_res;
int i;
code_resource.start = (unsigned long) &_text;
@ -464,7 +550,37 @@ setup_resources(void)
res->start = memory_chunk[i].addr;
res->end = memory_chunk[i].addr + memory_chunk[i].size - 1;
request_resource(&iomem_resource, res);
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)
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
setup_memory(void)
{
unsigned long bootmap_size;
unsigned long start_pfn, end_pfn, init_pfn;
unsigned long start_pfn, end_pfn;
int i;
/*
@ -514,10 +627,6 @@ setup_memory(void)
start_pfn = PFN_UP(__pa(&_end));
end_pfn = max_pfn = PFN_DOWN(memory_end);
/* Initialize storage key for kernel pages */
for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++)
page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
#ifdef CONFIG_BLK_DEV_INITRD
/*
* Move the initrd in case the bitmap of the bootmem allocater
@ -651,6 +760,7 @@ setup_arch(char **cmdline_p)
parse_early_param();
setup_memory_end();
setup_addressing_mode();
setup_memory();
setup_resources();
setup_lowcore();
@ -694,6 +804,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
struct cpuinfo_S390 *cpuinfo;
unsigned long n = (unsigned long) v - 1;
s390_adjust_jiffies();
preempt_disable();
if (!n) {
seq_printf(m, "vendor_id : IBM/S390\n"

View File

@ -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
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;
memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
memcpy(&user_sregs.regs.acrs, current->thread.acrs,

View File

@ -22,23 +22,23 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/spinlock.h>
#include <linux/kernel_stat.h>
#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/cache.h>
#include <linux/interrupt.h>
#include <linux/cpu.h>
#include <linux/timex.h>
#include <asm/setup.h>
#include <asm/sigp.h>
#include <asm/pgalloc.h>
#include <asm/irq.h>
#include <asm/s390_ext.h>
#include <asm/cpcmd.h>
#include <asm/tlbflush.h>
#include <asm/timer.h>
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];
/*
* 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_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);
static inline void do_send_stop(void)
static void do_send_stop(void)
{
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;
@ -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;
@ -250,7 +244,7 @@ static inline void do_wait_for_stop(void)
void smp_send_stop(void)
{
/* 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) */
lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
@ -298,7 +292,7 @@ void machine_power_off_smp(void)
* cpus are handled.
*/
void do_ext_call_interrupt(__u16 code)
static void do_ext_call_interrupt(__u16 code)
{
unsigned long bits;
@ -385,7 +379,7 @@ struct ec_creg_mask_parms {
/*
* 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;
unsigned long cregs[16];
int i;
@ -458,17 +452,15 @@ __init smp_count_cpus(void)
/*
* Activate a secondary processor.
*/
extern void init_cpu_timer(void);
extern void init_cpu_vtimer(void);
int __devinit start_secondary(void *cpuvoid)
{
/* Setup the cpu */
cpu_init();
preempt_disable();
/* init per CPU timer */
/* Enable TOD clock interrupts on the secondary cpu. */
init_cpu_timer();
#ifdef CONFIG_VIRT_TIMER
/* Enable cpu timer interrupts on the secondary cpu. */
init_cpu_vtimer();
#endif
/* Enable pfault pseudo page faults on this cpu. */
@ -542,7 +534,7 @@ smp_put_cpu(int cpu)
spin_unlock_irqrestore(&smp_reserve_lock, flags);
}
static inline int
static int
cpu_stopped(int cpu)
{
__u32 status;

View File

@ -11,7 +11,7 @@
#include <linux/stacktrace.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 long sp,
unsigned long low,

File diff suppressed because it is too large Load Diff

View File

@ -283,7 +283,7 @@ char *task_show_regs(struct task_struct *task, char *buffer)
return buffer;
}
DEFINE_SPINLOCK(die_lock);
static DEFINE_SPINLOCK(die_lock);
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);
}
asmlinkage void
default_trap_handler(struct pt_regs * regs, long interruption_code)
static void default_trap_handler(struct pt_regs * regs, long interruption_code)
{
if (regs->psw.mask & PSW_MASK_PSTATE) {
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) \
asmlinkage void name(struct pt_regs * regs, long interruption_code) \
static void name(struct pt_regs * regs, long interruption_code) \
{ \
siginfo_t info; \
info.si_signo = signr; \
@ -442,7 +441,7 @@ do_fp_trap(struct pt_regs *regs, void __user *location,
"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;
__u8 opcode[6];
@ -491,8 +490,15 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
#endif
} else
signal = SIGILL;
} else
} else {
/*
* 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
if (signal == SIGFPE)
@ -585,7 +591,7 @@ DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
ILL_ILLOPN, get_check_address(regs));
#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;
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;

View File

@ -31,19 +31,20 @@ SECTIONS
_etext = .; /* End of text section */
. = ALIGN(16); /* Exception table */
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
RODATA
#ifdef CONFIG_SHARED_KERNEL
. = ALIGN(1048576); /* VM shared segments are 1MB aligned */
_eshared = .; /* End of shareable data */
#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)
CONSTRUCTORS

View File

@ -25,7 +25,7 @@
#include <asm/irq_regs.h>
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
/*
@ -524,16 +524,15 @@ EXPORT_SYMBOL(del_virt_timer);
void init_cpu_vtimer(void)
{
struct vtimer_queue *vt_list;
unsigned long cr0;
/* kick the virtual timer */
S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
__ctl_store(cr0, 0, 0);
cr0 |= 0x400;
__ctl_load(cr0, 0, 0);
/* enable cpu timer interrupts */
__ctl_set_bit(0,10);
vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
INIT_LIST_HEAD(&vt_list->list);
@ -572,6 +571,7 @@ void __init vtime_init(void)
if (register_idle_notifier(&vtimer_idle_nb))
panic("Couldn't register idle notifier");
/* Enable cpu timer interrupts on the boot cpu. */
init_cpu_vtimer();
}

View File

@ -4,7 +4,7 @@
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_64BIT) += uaccess_mvcos.o
lib-$(CONFIG_SMP) += spinlock.o

View File

@ -1,5 +1,5 @@
/*
* arch/s390/kernel/delay.c
* arch/s390/lib/delay.c
* Precise Delay Loops for S390
*
* S390 version
@ -13,10 +13,8 @@
#include <linux/sched.h>
#include <linux/delay.h>
#ifdef CONFIG_SMP
#include <asm/smp.h>
#endif
#include <linux/timex.h>
#include <linux/irqflags.h>
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
* of the virtual PU inbetween to avoid congestion.
* Waits for 'usecs' microseconds using the TOD clock comparator.
*/
void __udelay(unsigned long usecs)
{
uint64_t start_cc;
u64 end, time, jiffy_timer = 0;
unsigned long flags, cr0, mask, dummy;
if (usecs == 0)
return;
start_cc = get_clock();
local_irq_save(flags);
if (raw_irqs_disabled_flags(flags)) {
jiffy_timer = S390_lowcore.jiffy_timer;
S390_lowcore.jiffy_timer = -1ULL - (4096 << 12);
__ctl_store(cr0, 0, 0);
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 {
cpu_relax();
} while (((get_clock() - start_cc)/4096) < usecs);
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
View 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
View 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 */

View File

@ -12,6 +12,7 @@
#include <linux/mm.h>
#include <asm/uaccess.h>
#include <asm/futex.h>
#include "uaccess.h"
#ifndef __s390x__
#define AHI "ahi"
@ -27,10 +28,7 @@
#define SLR "slgr"
#endif
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 *);
size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
{
register unsigned long reg0 asm("0") = 0x81UL;
unsigned long tmp1, tmp2;
@ -69,14 +67,14 @@ size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
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)
return copy_from_user_std(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;
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;
}
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)
return copy_to_user_std(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;
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;
}
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;
unsigned long tmp1, tmp2;
@ -162,10 +162,43 @@ size_t clear_user_mvcos(size_t size, void __user *to)
return size;
}
extern size_t strnlen_user_std(size_t, const char __user *);
extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
extern int futex_atomic_op(int, int __user *, int, int *);
extern int futex_atomic_cmpxchg(int __user *, int, int);
static size_t strnlen_user_mvcos(size_t count, const char __user *src)
{
char buf[256];
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 = {
.copy_from_user = copy_from_user_mvcos_check,
@ -176,6 +209,21 @@ struct uaccess_ops uaccess_mvcos = {
.clear_user = clear_user_mvcos,
.strnlen_user = strnlen_user_std,
.strncpy_from_user = strncpy_from_user_std,
.futex_atomic_op = futex_atomic_op,
.futex_atomic_cmpxchg = futex_atomic_cmpxchg,
.futex_atomic_op = futex_atomic_op_std,
.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

View File

@ -1,7 +1,8 @@
/*
* 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
* Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com)
@ -12,8 +13,9 @@
#include <linux/mm.h>
#include <asm/uaccess.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)
{
struct vm_area_struct *vma;
@ -79,7 +81,7 @@ out_sigbus:
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)
{
struct mm_struct *mm = current->mm;
@ -133,6 +135,49 @@ fault:
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 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);
}
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(&current->mm->page_table_lock);
uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
if (!uaddr) {
spin_unlock(&current->mm->page_table_lock);
return -EFAULT;
}
get_page(virt_to_page(uaddr));
spin_unlock(&current->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(&current->mm->page_table_lock);
uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
if (!uaddr) {
spin_unlock(&current->mm->page_table_lock);
return -EFAULT;
}
get_page(virt_to_page(uaddr));
spin_unlock(&current->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,
};

View File

@ -13,6 +13,7 @@
#include <linux/mm.h>
#include <linux/uaccess.h>
#include <asm/futex.h>
#include "uaccess.h"
#ifndef __s390x__
#define AHI "ahi"
@ -28,9 +29,6 @@
#define SLR "slgr"
#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)
{
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;
}
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)
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;
}
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)
return copy_to_user_std(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;
@ -148,7 +149,7 @@ size_t copy_in_user_std(size_t size, void __user *to, const void __user *from)
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;
@ -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), \
"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;
@ -286,7 +287,7 @@ int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old)
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;
@ -311,6 +312,6 @@ struct uaccess_ops uaccess_std = {
.clear_user = clear_user_std,
.strnlen_user = strnlen_user_std,
.strncpy_from_user = strncpy_from_user_std,
.futex_atomic_op = futex_atomic_op,
.futex_atomic_cmpxchg = futex_atomic_cmpxchg,
.futex_atomic_op = futex_atomic_op_std,
.futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
};

View File

@ -2,7 +2,7 @@
# 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_AFLAGS := -traditional

View File

@ -15,7 +15,7 @@
#include <asm/uaccess.h>
#include <asm/lowcore.h>
#include "sfp-util.h"
#include <asm/sfp-util.h>
#include <math-emu/soft-fp.h>
#include <math-emu/single.h>
#include <math-emu/double.h>

View File

@ -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

View File

@ -245,7 +245,7 @@ cmm_set_timeout(long nr, long seconds)
cmm_set_timer();
}
static inline int
static int
cmm_skip_blanks(char *cp, char **endp)
{
char *str;
@ -414,7 +414,7 @@ cmm_smsg_target(char *from, char *msg)
}
#endif
struct ctl_table_header *cmm_sysctl_header;
static struct ctl_table_header *cmm_sysctl_header;
static int
cmm_init (void)

View File

@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/bootmem.h>
#include <linux/ctype.h>
#include <linux/ioport.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/ebcdic.h>
@ -70,6 +71,7 @@ struct qin64 {
struct dcss_segment {
struct list_head list;
char dcss_name[8];
char res_name[15];
unsigned long start_addr;
unsigned long end;
atomic_t ref_count;
@ -77,6 +79,7 @@ struct dcss_segment {
unsigned int vm_segtype;
struct qrange range[6];
int segcnt;
struct resource *res;
};
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
* an ascii name.
*/
static void inline
static void
dcss_mkname(char *name, char *dcss_name)
{
int i;
@ -303,6 +306,29 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
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)
dcss_command = DCSS_LOADNSR;
else
@ -316,12 +342,11 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
rc = dcss_diag_translate_rc (seg->end);
dcss_diag(DCSS_PURGESEG, seg->dcss_name,
&seg->start_addr, &seg->end);
goto out_shared;
goto out_resource;
}
seg->do_nonshared = do_nonshared;
atomic_set(&seg->ref_count, 1);
list_add(&seg->list, &dcss_list);
rc = seg->vm_segtype;
*addr = seg->start_addr;
*end = seg->end;
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,
(void*)seg->start_addr, (void*)seg->end,
segtype_string[seg->vm_segtype]);
else
else {
PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
"type %s in shared mode\n", name,
(void*)seg->start_addr, (void*)seg->end,
segtype_string[seg->vm_segtype]);
}
goto out;
out_resource:
release_resource(seg->res);
kfree(seg->res);
out_shared:
remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
out_free:
@ -401,6 +430,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr,
* -ENOENT : no such segment (segment gone!)
* -EAGAIN : segment is in use by other exploiters, try later
* -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
*/
int
@ -428,12 +458,24 @@ segment_modify_shared (char *name, int do_nonshared)
rc = -EAGAIN;
goto out_unlock;
}
dcss_diag(DCSS_PURGESEG, seg->dcss_name,
&dummy, &dummy);
if (do_nonshared)
release_resource(seg->res);
if (do_nonshared) {
dcss_command = DCSS_LOADNSR;
else
seg->res->flags &= ~IORESOURCE_READONLY;
} 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,
&seg->start_addr, &seg->end);
if (diag_cc > 1) {
@ -446,9 +488,9 @@ segment_modify_shared (char *name, int do_nonshared)
rc = 0;
goto out_unlock;
out_del:
remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
list_del(&seg->list);
dcss_diag(DCSS_PURGESEG, seg->dcss_name,
&dummy, &dummy);
dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
kfree(seg);
out_unlock:
mutex_unlock(&dcss_lock);
@ -478,6 +520,8 @@ segment_unload(char *name)
}
if (atomic_dec_return(&seg->ref_count) != 0)
goto out_unlock;
release_resource(seg->res);
kfree(seg->res);
remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
list_del(&seg->list);
dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);

View File

@ -52,7 +52,7 @@ extern int sysctl_userprocess_debug;
extern void die(const char *,struct pt_regs *,long);
#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)
{
return atomic_notifier_chain_register(&notify_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.
* 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)
{
@ -154,7 +156,7 @@ static inline int check_user_space(struct pt_regs *regs, int error_code)
return __check_access_register(regs, error_code);
if (descriptor == 2)
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);
}
#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,
* 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);
if (!vma)
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)
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
@ -452,8 +536,7 @@ void pfault_fini(void)
: : "a" (&refbk), "m" (refbk) : "cc");
}
asmlinkage void
pfault_interrupt(__u16 error_code)
static void pfault_interrupt(__u16 error_code)
{
struct task_struct *tsk;
__u16 subcode;

View File

@ -25,7 +25,7 @@
#include <linux/bootmem.h>
#include <linux/pfn.h>
#include <linux/poison.h>
#include <linux/initrd.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@ -95,20 +95,18 @@ static void __init setup_ro_region(void)
pte_t new_pte;
unsigned long address, end;
address = ((unsigned long)&__start_rodata) & PAGE_MASK;
end = PFN_ALIGN((unsigned long)&__end_rodata);
address = ((unsigned long)&_stext) & PAGE_MASK;
end = PFN_ALIGN((unsigned long)&_eshared);
for (; address < end; address += PAGE_SIZE) {
pgd = pgd_offset_k(address);
pmd = pmd_offset(pgd, address);
pte = pte_offset_kernel(pmd, address);
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
*/
@ -125,11 +123,11 @@ void __init paging_init(void)
#ifdef CONFIG_64BIT
pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE;
for (i = 0; i < PTRS_PER_PGD; i++)
pgd_clear(pg_dir + i);
pgd_clear_kernel(pg_dir + i);
#else
pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
for (i = 0; i < PTRS_PER_PGD; i++)
pmd_clear((pmd_t *)(pg_dir + i));
pmd_clear_kernel((pmd_t *)(pg_dir + i));
#endif
vmem_map_init();
setup_ro_region();
@ -174,10 +172,8 @@ void __init mem_init(void)
datasize >>10,
initsize >> 10);
printk("Write protected kernel read-only data: %#lx - %#lx\n",
(unsigned long)&__start_rodata,
PFN_ALIGN((unsigned long)&__end_rodata) - 1);
printk("Virtual memmap size: %ldk\n",
(max_pfn * sizeof(struct page)) >> 10);
(unsigned long)&_stext,
PFN_ALIGN((unsigned long)&_eshared) - 1);
}
void free_initmem(void)

View File

@ -82,7 +82,7 @@ static inline pmd_t *vmem_pmd_alloc(void)
if (!pmd)
return NULL;
for (i = 0; i < PTRS_PER_PMD; i++)
pmd_clear(pmd + i);
pmd_clear_kernel(pmd + i);
return pmd;
}
@ -97,7 +97,7 @@ static inline pte_t *vmem_pte_alloc(void)
return NULL;
pte_val(empty_pte) = _PAGE_TYPE_EMPTY;
for (i = 0; i < PTRS_PER_PTE; i++)
set_pte(pte + i, empty_pte);
pte[i] = empty_pte;
return pte;
}
@ -119,7 +119,7 @@ static int vmem_add_range(unsigned long start, unsigned long size)
pm_dir = vmem_pmd_alloc();
if (!pm_dir)
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);
@ -132,7 +132,7 @@ static int vmem_add_range(unsigned long start, unsigned long size)
pt_dir = pte_offset_kernel(pm_dir, address);
pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL);
set_pte(pt_dir, pte);
*pt_dir = pte;
}
ret = 0;
out:
@ -161,7 +161,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
if (pmd_none(*pm_dir))
continue;
pt_dir = pte_offset_kernel(pm_dir, address);
set_pte(pt_dir, pte);
*pt_dir = pte;
}
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();
if (!pm_dir)
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);
@ -210,7 +210,7 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size)
if (!new_page)
goto out;
pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL);
set_pte(pt_dir, pte);
*pt_dir = pte;
}
}
ret = 0;

View File

@ -74,14 +74,6 @@ config CRYPTO_SHA1
help
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
tristate "SHA256 digest algorithm"
select CRYPTO_ALGAPI
@ -91,17 +83,6 @@ config CRYPTO_SHA256
This version of SHA implements a 256 bit hash with 128 bits of
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
tristate "SHA384 and SHA512 digest algorithms"
select CRYPTO_ALGAPI
@ -187,14 +168,6 @@ config CRYPTO_DES
help
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
tristate "Blowfish cipher algorithm"
select CRYPTO_ALGAPI
@ -336,28 +309,6 @@ config CRYPTO_AES_X86_64
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
tristate "CAST5 (CAST-128) cipher algorithm"
select CRYPTO_ALGAPI

View File

@ -51,6 +51,8 @@ config CRYPTO_DEV_PADLOCK_SHA
If unsure say M. The compiled module will be
called padlock-sha.ko
source "arch/s390/crypto/Kconfig"
config CRYPTO_DEV_GEODE
tristate "Support for the Geode LX AES engine"
depends on CRYPTO && X86_32 && PCI

View File

@ -103,14 +103,8 @@ config CCW_CONSOLE
depends on TN3215_CONSOLE || TN3270_CONSOLE
default y
config SCLP
bool "Support for SCLP"
help
Include support for the SCLP interface to the service element.
config SCLP_TTY
bool "Support for SCLP line mode terminal"
depends on SCLP
help
Include support for IBM SCLP line-mode terminals.
@ -123,7 +117,6 @@ config SCLP_CONSOLE
config SCLP_VT220_TTY
bool "Support for SCLP VT220-compatible terminal"
depends on SCLP
help
Include support for an IBM SCLP VT220-compatible terminal.
@ -136,7 +129,6 @@ config SCLP_VT220_CONSOLE
config SCLP_CPI
tristate "Control-Program Identification"
depends on SCLP
help
This option enables the hardware console interface for system
identification. This is commonly used for workload management and

View File

@ -2,6 +2,8 @@
# 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 += cio/ block/ char/ crypto/ net/ scsi/

View File

@ -37,6 +37,7 @@
*/
debug_info_t *dasd_debug_area;
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_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_free_queue(struct dasd_device * 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 void dasd_tasklet(struct dasd_device *);
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.
*/
static inline void
static void
dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
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.
*/
static inline void
static void
dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
struct request *req)
{
@ -1022,8 +1022,6 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
irb->scsw.cstat == 0 &&
!irb->esw.esw0.erw.cons)
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)
era = device->discipline->examine_error(cqr, irb);
else
@ -1104,7 +1102,7 @@ __dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr)
/*
* Process ccw request queue.
*/
static inline void
static void
__dasd_process_ccw_queue(struct dasd_device * device,
struct list_head *final_queue)
{
@ -1127,7 +1125,9 @@ restart:
cqr->status = DASD_CQR_FAILED;
cqr->stopclk = get_clock();
} 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_action(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.
*/
static inline void
static void
__dasd_process_blk_queue(struct dasd_device * device)
{
request_queue_t *queue;
@ -1232,6 +1232,19 @@ __dasd_process_blk_queue(struct dasd_device * device)
if (IS_ERR(cqr)) {
if (PTR_ERR(cqr) == -ENOMEM)
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,
"CCW creation failed (rc=%ld) "
"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
* if it reached its expire time. If so, terminate the IO.
*/
static inline void
static void
__dasd_check_expire(struct dasd_device * device)
{
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
* if it needs to be started.
*/
static inline void
static void
__dasd_start_head(struct dasd_device * device)
{
struct dasd_ccw_req *cqr;

View File

@ -170,7 +170,6 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
/* log the erp chain if fatal error occurred */
if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
dasd_log_sense(cqr, irb);
dasd_log_ccw(cqr, 0, irb->scsw.cpa);
}
return era;
@ -2640,7 +2639,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
struct dasd_ccw_req *erp = NULL;
struct dasd_device *device = cqr->device;
__u32 cpa = cqr->irb.scsw.cpa;
struct dasd_ccw_req *temp_erp = NULL;
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 */
if (erp->status == DASD_CQR_FILLED) {
erp->status = DASD_CQR_QUEUED;

View File

@ -136,7 +136,7 @@ __setup ("dasd=", dasd_call_setup);
/*
* Read a device busid/devno from a string.
*/
static inline int
static int
dasd_busid(char **str, int *id0, int *id1, int *devno)
{
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
* is empty (value 0).
*/
static inline int
static int
dasd_feature_list(char *str, char **endp)
{
int features, len, rc;
@ -341,7 +341,7 @@ dasd_parse_range( char *parsestring ) {
return ERR_PTR(-EINVAL);
}
static inline char *
static char *
dasd_parse_next_element( char *parsestring ) {
char * residual_str;
residual_str = dasd_parse_keyword(parsestring);

View File

@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");
#define DIAG_MAX_RETRIES 32
#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_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
* number of blocks on the device minus the specified offset. Return non-zero
* otherwise. */
static __inline__ int
static inline int
mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
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
* otherwise. */
static __inline__ int
static inline int
mdsk_term_io(struct dasd_device * device)
{
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");
}
struct dasd_discipline dasd_diag_discipline = {
static struct dasd_discipline dasd_diag_discipline = {
.owner = THIS_MODULE,
.name = "DIAG",
.ebcname = "DIAG",

View File

@ -134,44 +134,7 @@ ceil_quot(unsigned int d1, unsigned int d2)
return (d1 + (d2 - 1)) / d2;
}
static inline 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
static unsigned int
recs_per_track(struct dasd_eckd_characteristics * rdc,
unsigned int kl, unsigned int dl)
{
@ -204,37 +167,39 @@ recs_per_track(struct dasd_eckd_characteristics * rdc,
return 0;
}
static inline void
static int
check_XRC (struct ccw1 *de_ccw,
struct DE_eckd_data *data,
struct dasd_device *device)
{
struct dasd_eckd_private *private;
int rc;
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 */
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->ep_sys_time = get_clock ();
rc = get_sync_clock(&data->ep_sys_time);
/* Ignore return code if sync clock is switched off. */
if (rc == -ENOSYS || rc == -EACCES)
rc = 0;
de_ccw->count = sizeof (struct DE_eckd_data);
de_ccw->flags |= CCW_FLAG_SLI;
}
return rc;
}
return;
} /* end check_XRC */
static inline void
static int
define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
int totrk, int cmd, struct dasd_device * device)
{
struct dasd_eckd_private *private;
struct ch_t geo, beg, end;
int rc = 0;
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:
data->mask.perm = 0x02;
data->attributes.operation = private->attrib.operation;
check_XRC (ccw, data, device);
rc = check_XRC (ccw, data, device);
break;
case DASD_ECKD_CCW_WRITE_CKD:
case DASD_ECKD_CCW_WRITE_CKD_MT:
data->attributes.operation = DASD_BYPASS_CACHE;
check_XRC (ccw, data, device);
rc = check_XRC (ccw, data, device);
break;
case DASD_ECKD_CCW_ERASE:
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.auth = 0x1;
data->attributes.operation = DASD_BYPASS_CACHE;
check_XRC (ccw, data, device);
rc = check_XRC (ccw, data, device);
break;
default:
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->end_ext.cyl = end.cyl;
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,
int rec_on_trk, int no_rec, int cmd,
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.
*/
struct dasd_ccw_req *
static struct dasd_ccw_req *
dasd_eckd_build_psf_ssc(struct dasd_device *device)
{
struct dasd_ccw_req *cqr;
@ -1200,7 +1166,12 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
return cqr;
ccw = cqr->cpaddr;
/* 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. */
idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
LO_data = (struct LO_eckd_data *) (idaws + cidaw);
@ -1380,7 +1351,7 @@ dasd_eckd_release(struct dasd_device *device)
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &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->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@ -1420,7 +1391,7 @@ dasd_eckd_reserve(struct dasd_device *device)
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &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->buildclk = get_clock();
cqr->status = DASD_CQR_FILLED;
@ -1459,7 +1430,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
cqr->device = device;
clear_bit(DASD_CQR_FLAGS_USE_ERP, &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->buildclk = get_clock();
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
* and return number of printed chars.
*/
static inline int
static int
dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
{
int len, count;

View File

@ -658,18 +658,24 @@ static struct file_operations dasd_eer_fops = {
.owner = THIS_MODULE,
};
static struct miscdevice dasd_eer_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "dasd_eer",
.fops = &dasd_eer_fops,
};
static struct miscdevice *dasd_eer_dev = NULL;
int __init dasd_eer_init(void)
{
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) {
kfree(dasd_eer_dev);
dasd_eer_dev = NULL;
MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
"register misc device");
return rc;
@ -680,5 +686,9 @@ int __init dasd_eer_init(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;
}
}

View File

@ -152,25 +152,6 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
} /* 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
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);
}
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_postaction);
EXPORT_SYMBOL(dasd_alloc_erp_request);
EXPORT_SYMBOL(dasd_free_erp_request);
EXPORT_SYMBOL(dasd_log_sense);
EXPORT_SYMBOL(dasd_log_ccw);

View File

@ -75,7 +75,7 @@ static struct ccw_driver dasd_fba_driver = {
.notify = dasd_generic_notify,
};
static inline void
static void
define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
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;
}
static inline void
static void
locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
int block_nr, int block_ct)
{

View File

@ -147,7 +147,7 @@ dasd_destroy_partitions(struct dasd_device * device)
*/
memset(&bpart, 0, sizeof(struct blkpg_partition));
memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
barg.data = (void __user *) &bpart;
barg.data = (void __force __user *) &bpart;
barg.op = BLKPG_DEL_PARTITION;
for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);

View File

@ -559,7 +559,6 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
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_ccw(struct dasd_ccw_req *, int, __u32);
/* externals in dasd_3370_erp.c */
dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);

View File

@ -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_statistics_entry = NULL;
static inline char *
static char *
dasd_get_user_string(const char __user *user_buf, size_t user_len)
{
char *buffer;
@ -154,7 +154,7 @@ static struct file_operations dasd_devices_file_ops = {
.release = seq_release,
};
static inline int
static int
dasd_calc_metrics(char *page, char **start, off_t off,
int count, int *eof, int len)
{
@ -167,8 +167,8 @@ dasd_calc_metrics(char *page, char **start, off_t off,
return len;
}
static inline char *
dasd_statistics_array(char *str, int *array, int shift)
static char *
dasd_statistics_array(char *str, unsigned int *array, int shift)
{
int i;

View File

@ -102,7 +102,7 @@ dcssblk_release_segment(struct device *dev)
* device needs to be enqueued before the semaphore is
* freed.
*/
static inline int
static int
dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
{
int minor, found;
@ -230,7 +230,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
SEGMENT_SHARED);
if (rc < 0) {
BUG_ON(rc == -EINVAL);
if (rc == -EIO || rc == -ENOENT)
if (rc != -EAGAIN)
goto removeseg;
} else {
dev_info->is_shared = 1;
@ -253,7 +253,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
SEGMENT_EXCLUSIVE);
if (rc < 0) {
BUG_ON(rc == -EINVAL);
if (rc == -EIO || rc == -ENOENT)
if (rc != -EAGAIN)
goto removeseg;
} else {
dev_info->is_shared = 0;

View File

@ -2,7 +2,8 @@
# 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_CONSOLE) += con3270.o
@ -11,7 +12,6 @@ obj-$(CONFIG_TN3270_FS) += fs3270.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_CONSOLE) += sclp_con.o
obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o

View File

@ -1121,7 +1121,7 @@ static const struct tty_operations tty3215_ops = {
* 3215 tty registration code called from tty_init().
* Most kernel services (incl. kmalloc) are available at this poimt.
*/
int __init
static int __init
tty3215_init(void)
{
struct tty_driver *driver;

View File

@ -69,8 +69,7 @@ static void con3270_update(struct con3270 *);
/*
* Setup timeout for a device. On timeout trigger an update.
*/
void
con3270_set_timer(struct con3270 *cp, int expires)
static void con3270_set_timer(struct con3270 *cp, int expires)
{
if (expires == 0) {
if (timer_pending(&cp->timer))

View File

@ -5,6 +5,8 @@
#include <linux/types.h>
#include <linux/keyboard.h>
#include <linux/kd.h>
#include <linux/kbd_kern.h>
#include <linux/kbd_diacr.h>
u_short plain_map[NR_KEYS] = {
0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,

View File

@ -23,7 +23,7 @@
#include "raw3270.h"
#include "ctrlchar.h"
struct raw3270_fn fs3270_fn;
static struct raw3270_fn fs3270_fn;
struct fs3270 {
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. */
struct raw3270_fn fs3270_fn = {
static struct raw3270_fn fs3270_fn = {
.activate = fs3270_activate,
.deactivate = fs3270_deactivate,
.intv = (void *) fs3270_irq,

View File

@ -148,6 +148,7 @@ kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc)
}
}
#if 0
/*
* 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.

View File

@ -67,7 +67,7 @@ static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
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 mon_buf *entry, *next;

View File

@ -29,7 +29,7 @@
#include <linux/device.h>
#include <linux/mutex.h>
struct class *class3270;
static struct class *class3270;
/* The main 3270 data structure. */
struct raw3270 {
@ -86,7 +86,7 @@ DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
/*
* 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,
0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,

View File

@ -59,7 +59,8 @@ static volatile enum sclp_init_state_t {
/* Internal state: is a request active at the sclp? */
static volatile enum sclp_running_state_t {
sclp_running_state_idle,
sclp_running_state_running
sclp_running_state_running,
sclp_running_state_reset_pending
} sclp_running_state = sclp_running_state_idle;
/* Internal state: is a read request pending? */
@ -88,15 +89,15 @@ static volatile enum sclp_mask_state_t {
/* Timeout intervals in seconds.*/
#define SCLP_BUSY_INTERVAL 10
#define SCLP_RETRY_INTERVAL 15
#define SCLP_RETRY_INTERVAL 30
static void sclp_process_queue(void);
static int sclp_init_mask(int calculate);
static int sclp_init(void);
/* Perform service call. Return 0 on success, non-zero otherwise. */
static int
service_call(sclp_cmdw_t command, void *sccb)
int
sclp_service_call(sclp_cmdw_t command, void *sccb)
{
int cc;
@ -113,19 +114,17 @@ service_call(sclp_cmdw_t command, void *sccb)
return 0;
}
/* 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;
static inline void __sclp_make_read_req(void);
if (data) {
spin_lock_irqsave(&sclp_lock, flags);
sclp_running_state = sclp_running_state_idle;
spin_unlock_irqrestore(&sclp_lock, flags);
static void
__sclp_queue_read_req(void)
{
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. */
@ -140,6 +139,29 @@ __sclp_set_request_timer(unsigned long time, void (*function)(unsigned long),
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
* started or if it will be started at a later time. Return non-zero otherwise.
* 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)
return 0;
del_timer(&sclp_request_timer);
rc = service_call(req->command, req->sccb);
rc = sclp_service_call(req->command, req->sccb);
req->start_count++;
if (rc == 0) {
@ -191,7 +213,15 @@ sclp_process_queue(void)
rc = __sclp_start_request(req);
if (rc == 0)
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);
if (req->callback) {
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);
rc = 0;
/* 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);
if (rc)
list_del(&req->list);
@ -294,7 +325,7 @@ __sclp_make_read_req(void)
sccb = (struct sccb_header *) sclp_read_sccb;
clear_page(sccb);
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.start_count = 0;
sclp_read_req.callback = sclp_read_cb;
@ -334,6 +365,8 @@ sclp_interrupt_handler(__u16 code)
finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
evbuf_pending = S390_lowcore.ext_params & 0x3;
if (finished_sccb) {
del_timer(&sclp_request_timer);
sclp_running_state = sclp_running_state_reset_pending;
req = __sclp_find_req(finished_sccb);
if (req) {
/* Request post-processing */
@ -348,13 +381,8 @@ sclp_interrupt_handler(__u16 code)
sclp_running_state = sclp_running_state_idle;
}
if (evbuf_pending && sclp_receive_mask != 0 &&
sclp_reading_state == sclp_reading_state_idle &&
sclp_activation_state == sclp_activation_state_active ) {
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_activation_state == sclp_activation_state_active)
__sclp_queue_read_req();
spin_unlock(&sclp_lock);
sclp_process_queue();
}
@ -374,6 +402,7 @@ sclp_sync_wait(void)
unsigned long flags;
unsigned long cr0, cr0_sync;
u64 timeout;
int irq_context;
/* We'll be disabling timer interrupts, so we need a custom timeout
* mechanism */
@ -386,6 +415,8 @@ sclp_sync_wait(void)
}
local_irq_save(flags);
/* Prevent bottom half from executing once we force interrupts open */
irq_context = in_interrupt();
if (!irq_context)
local_bh_disable();
/* Enable service-signal interruption, disable timer interrupts */
trace_hardirqs_on();
@ -402,11 +433,11 @@ sclp_sync_wait(void)
get_clock() > timeout &&
del_timer(&sclp_request_timer))
sclp_request_timer.function(sclp_request_timer.data);
barrier();
cpu_relax();
}
local_irq_disable();
__ctl_load(cr0, 0, 0);
if (!irq_context)
_local_bh_enable();
local_irq_restore(flags);
}
@ -414,7 +445,7 @@ sclp_sync_wait(void)
EXPORT_SYMBOL(sclp_sync_wait);
/* Dispatch changes in send and receive mask to registered listeners. */
static inline void
static void
sclp_dispatch_state_change(void)
{
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;
clear_page(sccb);
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.start_count = 0;
sclp_init_req.callback = NULL;
@ -800,7 +831,7 @@ sclp_check_interface(void)
for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) {
__sclp_make_init_req(0, 0);
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)
break;
sclp_init_req.status = SCLP_REQ_RUNNING;

View File

@ -12,7 +12,7 @@
#include <linux/types.h>
#include <linux/list.h>
#include <asm/sclp.h>
#include <asm/ebcdic.h>
/* maximum number of pages concerning our own memory management */
@ -49,9 +49,11 @@
typedef unsigned int sclp_cmdw_t;
#define SCLP_CMDW_READDATA 0x00770005
#define SCLP_CMDW_WRITEDATA 0x00760005
#define SCLP_CMDW_WRITEMASK 0x00780005
#define SCLP_CMDW_READ_EVENT_DATA 0x00770005
#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005
#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_MDSRouteInfo 0x1311
@ -66,13 +68,6 @@ typedef unsigned int sclp_cmdw_t;
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 {
u8 length;
u8 key;
@ -131,6 +126,7 @@ void sclp_unregister(struct sclp_register *reg);
int sclp_remove_processed(struct sccb_header *sccb);
int sclp_deactivate(void);
int sclp_reactivate(void);
int sclp_service_call(sclp_cmdw_t command, void *sccb);
/* useful inlines */

View File

@ -66,7 +66,7 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
} while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
}
static inline void
static void
sclp_conbuf_emit(void)
{
struct sclp_buffer* buffer;

View File

@ -169,7 +169,7 @@ cpi_prepare_req(void)
}
/* prepare request data structure presented to SCLP driver */
req->command = SCLP_CMDW_WRITEDATA;
req->command = SCLP_CMDW_WRITE_EVENT_DATA;
req->sccb = sccb;
req->status = SCLP_REQ_FILLED;
req->callback = cpi_callback;

View 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 */
}

View File

@ -460,7 +460,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
sccb->msg_buf.header.type = EvTyp_PMsgCmd;
else
return -ENOSYS;
buffer->request.command = SCLP_CMDW_WRITEDATA;
buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
buffer->request.status = SCLP_REQ_FILLED;
buffer->request.callback = sclp_writedata_callback;
buffer->request.callback_data = buffer;

View File

@ -721,7 +721,7 @@ static const struct tty_operations sclp_ops = {
.ioctl = sclp_tty_ioctl,
};
int __init
static int __init
sclp_tty_init(void)
{
struct tty_driver *driver;

Some files were not shown because too many files have changed in this diff Show More