提交 02aedd69 编写于 作者: L Linus Torvalds

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.
  ...
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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);
......
......@@ -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
......
......@@ -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
......
config CRYPTO_SHA1_S390
tristate "SHA1 digest algorithm"
depends on S390
select CRYPTO_ALGAPI
help
This is the s390 hardware accelerated implementation of the
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
config CRYPTO_SHA256_S390
tristate "SHA256 digest algorithm"
depends on S390
select CRYPTO_ALGAPI
help
This is the s390 hardware accelerated implementation of the
SHA256 secure hash standard (DFIPS 180-2).
This version of SHA implements a 256 bit hash with 128 bits of
security against collision attacks.
config CRYPTO_DES_S390
tristate "DES and Triple DES cipher algorithms"
depends on S390
select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
help
This us the s390 hardware accelerated implementation of the
DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
config CRYPTO_AES_S390
tristate "AES cipher algorithms"
depends on S390
select CRYPTO_ALGAPI
select CRYPTO_BLKCIPHER
help
This is the s390 hardware accelerated implementation of the
AES cipher algorithms (FIPS-197). AES uses the Rijndael
algorithm.
Rijndael appears to be consistently a very good performer in
both hardware and software across a wide range of computing
environments regardless of its use in feedback or non-feedback
modes. Its key setup time is excellent, and its key agility is
good. Rijndael's very low memory requirements make it very well
suited for restricted-space environments, in which it also
demonstrates excellent performance. Rijndael's operations are
among the easiest to defend against power and timing attacks.
On s390 the System z9-109 currently only supports the key size
of 128 bit.
config S390_PRNG
tristate "Pseudo random number generator device driver"
depends on S390
default "m"
help
Select this option if you want to use the s390 pseudo random number
generator. The PRNG is part of the cryptograhic processor functions
and uses triple-DES to generate secure random numbers like the
ANSI X9.17 standard. The PRNG is usable via the char device
/dev/prandom.
......@@ -6,5 +6,4 @@ obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o
obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o
obj-$(CONFIG_CRYPTO_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
......@@ -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 (!keylen_flag)
return -EOPNOTSUPP;
if (!has_aes_128 && !has_aes_192 && !has_aes_256)
return -ENOSYS;
/* 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;
......
......@@ -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,229 +105,219 @@ 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");
: "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_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.
* @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
*
* Returns -1 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)
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 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,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)
" 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");
: "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.
* @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
*
* 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)
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 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)
" 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" (-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;
}
/*
/**
* 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.
* @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
*
* 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)
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 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)
" 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" (-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;
}
/*
/**
* 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.
* @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
*
* 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)
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 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)
" 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" (-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;
}
/**
* 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.
* @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
*
* Returns 1 if func available; 0 if func or op in general not available
*/
static inline int
crypt_s390_func_available(int func)
static inline int crypt_s390_func_available(int func)
{
unsigned char status[16];
int ret;
struct crypt_s390_query_status status = {
.high = 0,
.low = 0
};
switch (func & CRYPT_S390_OP_MASK){
case CRYPT_S390_KM:
ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
break;
case CRYPT_S390_KMC:
ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
break;
case CRYPT_S390_KIMD:
ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
break;
case CRYPT_S390_KLMD:
ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
break;
case CRYPT_S390_KMAC:
ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
break;
default:
ret = 0;
return ret;
}
if (ret >= 0){
func &= CRYPT_S390_FUNC_MASK;
func &= 0x7f; //mask modifier bit
if (func < 64){
ret = (status.high >> (64 - func - 1)) & 0x1;
} else {
ret = (status.low >> (128 - func - 1)) & 0x1;
}
} else {
ret = 0;
switch (func & CRYPT_S390_OP_MASK) {
case CRYPT_S390_KM:
ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
break;
case CRYPT_S390_KMC:
ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
break;
case CRYPT_S390_KIMD:
ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
break;
case CRYPT_S390_KLMD:
ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
break;
case CRYPT_S390_KMAC:
ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
break;
default:
return 0;
}
return ret;
if (ret < 0)
return 0;
func &= CRYPT_S390_FUNC_MASK;
func &= 0x7f; /* mask modifier bit */
return (status[func >> 3] & (0x80 >> (func & 7))) != 0;
}
#endif // _CRYPTO_ARCH_S390_CRYPT_S390_H
#endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */
/*
* Cryptographic API.
*
* Support for s390 cryptographic instructions.
* Testing module for querying processor crypto capabilities.
*
* Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <asm/errno.h>
#include "crypt_s390.h"
static void query_available_functions(void)
{
printk(KERN_INFO "#####################\n");
/* query available KM functions */
printk(KERN_INFO "KM_QUERY: %d\n",
crypt_s390_func_available(KM_QUERY));
printk(KERN_INFO "KM_DEA: %d\n",
crypt_s390_func_available(KM_DEA_ENCRYPT));
printk(KERN_INFO "KM_TDEA_128: %d\n",
crypt_s390_func_available(KM_TDEA_128_ENCRYPT));
printk(KERN_INFO "KM_TDEA_192: %d\n",
crypt_s390_func_available(KM_TDEA_192_ENCRYPT));
printk(KERN_INFO "KM_AES_128: %d\n",
crypt_s390_func_available(KM_AES_128_ENCRYPT));
printk(KERN_INFO "KM_AES_192: %d\n",
crypt_s390_func_available(KM_AES_192_ENCRYPT));
printk(KERN_INFO "KM_AES_256: %d\n",
crypt_s390_func_available(KM_AES_256_ENCRYPT));
/* query available KMC functions */
printk(KERN_INFO "KMC_QUERY: %d\n",
crypt_s390_func_available(KMC_QUERY));
printk(KERN_INFO "KMC_DEA: %d\n",
crypt_s390_func_available(KMC_DEA_ENCRYPT));
printk(KERN_INFO "KMC_TDEA_128: %d\n",
crypt_s390_func_available(KMC_TDEA_128_ENCRYPT));
printk(KERN_INFO "KMC_TDEA_192: %d\n",
crypt_s390_func_available(KMC_TDEA_192_ENCRYPT));
printk(KERN_INFO "KMC_AES_128: %d\n",
crypt_s390_func_available(KMC_AES_128_ENCRYPT));
printk(KERN_INFO "KMC_AES_192: %d\n",
crypt_s390_func_available(KMC_AES_192_ENCRYPT));
printk(KERN_INFO "KMC_AES_256: %d\n",
crypt_s390_func_available(KMC_AES_256_ENCRYPT));
/* query available KIMD functions */
printk(KERN_INFO "KIMD_QUERY: %d\n",
crypt_s390_func_available(KIMD_QUERY));
printk(KERN_INFO "KIMD_SHA_1: %d\n",
crypt_s390_func_available(KIMD_SHA_1));
printk(KERN_INFO "KIMD_SHA_256: %d\n",
crypt_s390_func_available(KIMD_SHA_256));
/* query available KLMD functions */
printk(KERN_INFO "KLMD_QUERY: %d\n",
crypt_s390_func_available(KLMD_QUERY));
printk(KERN_INFO "KLMD_SHA_1: %d\n",
crypt_s390_func_available(KLMD_SHA_1));
printk(KERN_INFO "KLMD_SHA_256: %d\n",
crypt_s390_func_available(KLMD_SHA_256));
/* query available KMAC functions */
printk(KERN_INFO "KMAC_QUERY: %d\n",
crypt_s390_func_available(KMAC_QUERY));
printk(KERN_INFO "KMAC_DEA: %d\n",
crypt_s390_func_available(KMAC_DEA));
printk(KERN_INFO "KMAC_TDEA_128: %d\n",
crypt_s390_func_available(KMAC_TDEA_128));
printk(KERN_INFO "KMAC_TDEA_192: %d\n",
crypt_s390_func_available(KMAC_TDEA_192));
}
static int init(void)
{
struct crypt_s390_query_status status = {
.high = 0,
.low = 0
};
printk(KERN_INFO "crypt_s390: querying available crypto functions\n");
crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
printk(KERN_INFO "KM:\t%016llx %016llx\n",
(unsigned long long) status.high,
(unsigned long long) status.low);
status.high = status.low = 0;
crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
printk(KERN_INFO "KMC:\t%016llx %016llx\n",
(unsigned long long) status.high,
(unsigned long long) status.low);
status.high = status.low = 0;
crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
printk(KERN_INFO "KIMD:\t%016llx %016llx\n",
(unsigned long long) status.high,
(unsigned long long) status.low);
status.high = status.low = 0;
crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
printk(KERN_INFO "KLMD:\t%016llx %016llx\n",
(unsigned long long) status.high,
(unsigned long long) status.low);
status.high = status.low = 0;
crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
printk(KERN_INFO "KMAC:\t%016llx %016llx\n",
(unsigned long long) status.high,
(unsigned long long) status.low);
query_available_functions();
return -ECANCELED;
}
static void __exit cleanup(void)
{
}
module_init(init);
module_exit(cleanup);
MODULE_LICENSE("GPL");
......@@ -10,8 +10,9 @@
* scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL.
*
* 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))
......
......@@ -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)
......
/*
* Copyright IBM Corp. 2006,2007
* Author(s): Jan Glauber <jan.glauber@de.ibm.com>
* Driver for the s390 pseudo random number generator
*/
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/random.h>
#include <asm/debug.h>
#include <asm/uaccess.h>
#include "crypt_s390.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jan Glauber <jan.glauber@de.ibm.com>");
MODULE_DESCRIPTION("s390 PRNG interface");
static int prng_chunk_size = 256;
module_param(prng_chunk_size, int, S_IRUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes");
static int prng_entropy_limit = 4096;
module_param(prng_entropy_limit, int, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
MODULE_PARM_DESC(prng_entropy_limit,
"PRNG add entropy after that much bytes were produced");
/*
* Any one who considers arithmetical methods of producing random digits is,
* of course, in a state of sin. -- John von Neumann
*/
struct s390_prng_data {
unsigned long count; /* how many bytes were produced */
char *buf;
};
static struct s390_prng_data *p;
/* copied from libica, use a non-zero initial parameter block */
static unsigned char parm_block[32] = {
0x0F,0x2B,0x8E,0x63,0x8C,0x8E,0xD2,0x52,0x64,0xB7,0xA0,0x7B,0x75,0x28,0xB8,0xF4,
0x75,0x5F,0xD2,0xA6,0x8D,0x97,0x11,0xFF,0x49,0xD8,0x23,0xF3,0x7E,0x21,0xEC,0xA0,
};
static int prng_open(struct inode *inode, struct file *file)
{
return nonseekable_open(inode, file);
}
static void prng_add_entropy(void)
{
__u64 entropy[4];
unsigned int i;
int ret;
for (i = 0; i < 16; i++) {
ret = crypt_s390_kmc(KMC_PRNG, parm_block, (char *)entropy,
(char *)entropy, sizeof(entropy));
BUG_ON(ret < 0 || ret != sizeof(entropy));
memcpy(parm_block, entropy, sizeof(entropy));
}
}
static void prng_seed(int nbytes)
{
char buf[16];
int i = 0;
BUG_ON(nbytes > 16);
get_random_bytes(buf, nbytes);
/* Add the entropy */
while (nbytes >= 8) {
*((__u64 *)parm_block) ^= *((__u64 *)buf+i*8);
prng_add_entropy();
i += 8;
nbytes -= 8;
}
prng_add_entropy();
}
static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
loff_t *ppos)
{
int chunk, n;
int ret = 0;
int tmp;
/* nbytes can be arbitrary long, we spilt it into chunks */
while (nbytes) {
/* same as in extract_entropy_user in random.c */
if (need_resched()) {
if (signal_pending(current)) {
if (ret == 0)
ret = -ERESTARTSYS;
break;
}
schedule();
}
/*
* we lose some random bytes if an attacker issues
* reads < 8 bytes, but we don't care
*/
chunk = min_t(int, nbytes, prng_chunk_size);
/* PRNG only likes multiples of 8 bytes */
n = (chunk + 7) & -8;
if (p->count > prng_entropy_limit)
prng_seed(8);
/* if the CPU supports PRNG stckf is present too */
asm volatile(".insn s,0xb27c0000,%0"
: "=m" (*((unsigned long long *)p->buf)) : : "cc");
/*
* Beside the STCKF the input for the TDES-EDE is the output
* of the last operation. We differ here from X9.17 since we
* only store one timestamp into the buffer. Padding the whole
* buffer with timestamps does not improve security, since
* successive stckf have nearly constant offsets.
* If an attacker knows the first timestamp it would be
* trivial to guess the additional values. One timestamp
* is therefore enough and still guarantees unique input values.
*
* Note: you can still get strict X9.17 conformity by setting
* prng_chunk_size to 8 bytes.
*/
tmp = crypt_s390_kmc(KMC_PRNG, parm_block, p->buf, p->buf, n);
BUG_ON((tmp < 0) || (tmp != n));
p->count += n;
if (copy_to_user(ubuf, p->buf, chunk))
return -EFAULT;
nbytes -= chunk;
ret += chunk;
ubuf += chunk;
}
return ret;
}
static struct file_operations prng_fops = {
.owner = THIS_MODULE,
.open = &prng_open,
.release = NULL,
.read = &prng_read,
};
static struct miscdevice prng_dev = {
.name = "prandom",
.minor = MISC_DYNAMIC_MINOR,
.fops = &prng_fops,
};
static int __init prng_init(void)
{
int ret;
/* check if the CPU has a PRNG */
if (!crypt_s390_func_available(KMC_PRNG))
return -EOPNOTSUPP;
if (prng_chunk_size < 8)
return -EINVAL;
p = kmalloc(sizeof(struct s390_prng_data), GFP_KERNEL);
if (!p)
return -ENOMEM;
p->count = 0;
p->buf = kmalloc(prng_chunk_size, GFP_KERNEL);
if (!p->buf) {
ret = -ENOMEM;
goto out_free;
}
/* initialize the PRNG, add 128 bits of entropy */
prng_seed(16);
ret = misc_register(&prng_dev);
if (ret) {
printk(KERN_WARNING
"Could not register misc device for PRNG.\n");
goto out_buf;
}
return 0;
out_buf:
kfree(p->buf);
out_free:
kfree(p);
return ret;
}
static void __exit prng_exit(void)
{
/* wipe me */
memset(p->buf, 0, prng_chunk_size);
kfree(p->buf);
kfree(p);
misc_deregister(&prng_dev);
}
module_init(prng_init);
module_exit(prng_exit);
......@@ -8,8 +8,9 @@
* implementation written by Steve Reid.
*
* 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,13 +62,13 @@ 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);
SHA1_BLOCK_SIZE - sctx->buf_len);
crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer,
SHA1_BLOCK_SIZE);
data += SHA1_BLOCK_SIZE - sctx->buf_len;
......@@ -77,37 +76,36 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
sctx->buf_len = 0;
}
//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)?
SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
//start pad with 1
sctx->buf_len = (sctx->buf_len < 56) ?
SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
/* 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);
sizeof sctx->count);
}
/* Add padding and return the message digest. */
......@@ -115,47 +113,40 @@ static void sha1_final(struct crypto_tfm *tfm, u8 *out)
{
struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
//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,
.cra_ctxsize = sizeof(struct crypt_s390_sha1_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(alg.cra_list),
.cra_list = LIST_HEAD_INIT(alg.cra_list),
.cra_u = { .digest = {
.dia_digestsize = SHA1_DIGEST_SIZE,
.dia_init = sha1_init,
.dia_update = sha1_update,
.dia_final = sha1_final } }
.dia_init = sha1_init,
.dia_update = sha1_update,
.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);
}
......
......@@ -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)
......
......@@ -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
......
......@@ -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
......@@ -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_ */
/*
* 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_ */
/*
* Hypervisor filesystem for Linux on s390. z/VM implementation.
*
* Copyright (C) IBM Corp. 2006
* Author(s): Michael Holzheu <holzheu@de.ibm.com>
*/
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
#include <asm/ebcdic.h>
#include "hypfs.h"
#define NAME_LEN 8
static char local_guest[] = " ";
static char all_guests[] = "* ";
static char *guest_query;
struct diag2fc_data {
__u32 version;
__u32 flags;
__u64 used_cpu;
__u64 el_time;
__u64 mem_min_kb;
__u64 mem_max_kb;
__u64 mem_share_kb;
__u64 mem_used_kb;
__u32 pcpus;
__u32 lcpus;
__u32 vcpus;
__u32 cpu_min;
__u32 cpu_max;
__u32 cpu_shares;
__u32 cpu_use_samp;
__u32 cpu_delay_samp;
__u32 page_wait_samp;
__u32 idle_samp;
__u32 other_samp;
__u32 total_samp;
char guest_name[NAME_LEN];
};
struct diag2fc_parm_list {
char userid[NAME_LEN];
char aci_grp[NAME_LEN];
__u64 addr;
__u32 size;
__u32 fmt;
};
static int diag2fc(int size, char* query, void *addr)
{
unsigned long residual_cnt;
unsigned long rc;
struct diag2fc_parm_list parm_list;
memcpy(parm_list.userid, query, NAME_LEN);
ASCEBC(parm_list.userid, NAME_LEN);
parm_list.addr = (unsigned long) addr ;
parm_list.size = size;
parm_list.fmt = 0x02;
memset(parm_list.aci_grp, 0x40, NAME_LEN);
rc = -1;
asm volatile(
" diag %0,%1,0x2fc\n"
"0:\n"
EX_TABLE(0b,0b)
: "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
if ((rc != 0 ) && (rc != -2))
return rc;
else
return -residual_cnt;
}
static struct diag2fc_data *diag2fc_store(char *query, int *count)
{
int size;
struct diag2fc_data *data;
do {
size = diag2fc(0, query, NULL);
if (size < 0)
return ERR_PTR(-EACCES);
data = vmalloc(size);
if (!data)
return ERR_PTR(-ENOMEM);
if (diag2fc(size, query, data) == 0)
break;
vfree(data);
} while (1);
*count = (size / sizeof(*data));
return data;
}
static void diag2fc_free(void *data)
{
vfree(data);
}
#define ATTRIBUTE(sb, dir, name, member) \
do { \
void *rc; \
rc = hypfs_create_u64(sb, dir, name, member); \
if (IS_ERR(rc)) \
return PTR_ERR(rc); \
} while(0)
static int hpyfs_vm_create_guest(struct super_block *sb,
struct dentry *systems_dir,
struct diag2fc_data *data)
{
char guest_name[NAME_LEN + 1] = {};
struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
int dedicated_flag, capped_value;
capped_value = (data->flags & 0x00000006) >> 1;
dedicated_flag = (data->flags & 0x00000008) >> 3;
/* guest dir */
memcpy(guest_name, data->guest_name, NAME_LEN);
EBCASC(guest_name, NAME_LEN);
strstrip(guest_name);
guest_dir = hypfs_mkdir(sb, systems_dir, guest_name);
if (IS_ERR(guest_dir))
return PTR_ERR(guest_dir);
ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time);
/* logical cpu information */
cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus");
if (IS_ERR(cpus_dir))
return PTR_ERR(cpus_dir);
ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu);
ATTRIBUTE(sb, cpus_dir, "capped", capped_value);
ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag);
ATTRIBUTE(sb, cpus_dir, "count", data->vcpus);
ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min);
ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max);
ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares);
/* memory information */
mem_dir = hypfs_mkdir(sb, guest_dir, "mem");
if (IS_ERR(mem_dir))
return PTR_ERR(mem_dir);
ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb);
ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb);
ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb);
ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb);
/* samples */
samples_dir = hypfs_mkdir(sb, guest_dir, "samples");
if (IS_ERR(samples_dir))
return PTR_ERR(samples_dir);
ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp);
ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp);
ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp);
ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp);
ATTRIBUTE(sb, samples_dir, "other", data->other_samp);
ATTRIBUTE(sb, samples_dir, "total", data->total_samp);
return 0;
}
int hypfs_vm_create_files(struct super_block *sb, struct dentry *root)
{
struct dentry *dir, *file;
struct diag2fc_data *data;
int rc, i, count = 0;
data = diag2fc_store(guest_query, &count);
if (IS_ERR(data))
return PTR_ERR(data);
/* Hpervisor Info */
dir = hypfs_mkdir(sb, root, "hyp");
if (IS_ERR(dir)) {
rc = PTR_ERR(dir);
goto failed;
}
file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor");
if (IS_ERR(file)) {
rc = PTR_ERR(file);
goto failed;
}
/* physical cpus */
dir = hypfs_mkdir(sb, root, "cpus");
if (IS_ERR(dir)) {
rc = PTR_ERR(dir);
goto failed;
}
file = hypfs_create_u64(sb, dir, "count", data->lcpus);
if (IS_ERR(file)) {
rc = PTR_ERR(file);
goto failed;
}
/* guests */
dir = hypfs_mkdir(sb, root, "systems");
if (IS_ERR(dir)) {
rc = PTR_ERR(dir);
goto failed;
}
for (i = 0; i < count; i++) {
rc = hpyfs_vm_create_guest(sb, dir, &(data[i]));
if (rc)
goto failed;
}
diag2fc_free(data);
return 0;
failed:
diag2fc_free(data);
return rc;
}
int hypfs_vm_init(void)
{
if (diag2fc(0, all_guests, NULL) > 0)
guest_query = all_guests;
else if (diag2fc(0, local_guest, NULL) > 0)
guest_query = local_guest;
else
return -EACCES;
return 0;
}
......@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <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,7 +191,10 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
goto out;
}
hypfs_delete_tree(sb->s_root);
rc = hypfs_diag_create_files(sb, sb->s_root);
if (MACHINE_IS_VM)
rc = hypfs_vm_create_files(sb, sb->s_root);
else
rc = hypfs_diag_create_files(sb, sb->s_root);
if (rc) {
printk(KERN_ERR "hypfs: Update failed\n");
hypfs_delete_tree(sb->s_root);
......@@ -289,7 +291,10 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
rc = -ENOMEM;
goto err_alloc;
}
rc = hypfs_diag_create_files(sb, root_dentry);
if (MACHINE_IS_VM)
rc = hypfs_vm_create_files(sb, root_dentry);
else
rc = hypfs_diag_create_files(sb, root_dentry);
if (rc)
goto err_tree;
sbi->update_file = hypfs_create_update_file(sb, root_dentry);
......@@ -462,11 +467,15 @@ static int __init hypfs_init(void)
{
int rc;
if (MACHINE_IS_VM)
return -ENODATA;
if (hypfs_diag_init()) {
rc = -ENODATA;
goto fail_diag;
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);
......@@ -480,7 +489,8 @@ static int __init hypfs_init(void)
fail_filesystem:
subsystem_unregister(&s390_subsys);
fail_sysfs:
hypfs_diag_exit();
if (!MACHINE_IS_VM)
hypfs_diag_exit();
fail_diag:
printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
return rc;
......@@ -488,7 +498,8 @@ static int __init hypfs_init(void)
static void __exit hypfs_exit(void)
{
hypfs_diag_exit();
if (!MACHINE_IS_VM)
hypfs_diag_exit();
unregister_filesystem(&hypfs_type);
subsystem_unregister(&s390_subsys);
}
......
......@@ -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)
......
/*
* arch/s390/kernel/reset.S
* arch/s390/kernel/base.S
*
* Copyright (C) IBM Corp. 2006
* Copyright IBM Corp. 2006,2007
* Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
* Michael Holzheu <holzheu@de.ibm.com>
*/
......@@ -11,12 +11,13 @@
#ifdef CONFIG_64BIT
.globl reset_mcck_handler
reset_mcck_handler:
.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
lg %r1,s390_reset_mcck_handler-0b(%r13)
larl %r1,s390_base_mcck_handler_fn
lg %r1,0(%r1)
ltgr %r1,%r1
jz 1f
basr %r14,%r1
......@@ -24,55 +25,108 @@ reset_mcck_handler:
lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
lpswe __LC_MCK_OLD_PSW
.globl s390_reset_mcck_handler
s390_reset_mcck_handler:
.section .bss
.globl s390_base_mcck_handler_fn
s390_base_mcck_handler_fn:
.quad 0
.previous
.globl reset_pgm_handler
reset_pgm_handler:
.globl s390_base_ext_handler
s390_base_ext_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)
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)
.globl s390_reset_pgm_handler
s390_reset_pgm_handler:
.quad 0
.align 8
disabled_wait_psw:
.quad 0x0002000180000000,0x0000000000000000 + reset_pgm_handler
.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 reset_mcck_handler
reset_mcck_handler:
.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,s390_reset_mcck_handler-0b(%r13)
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
.globl s390_reset_mcck_handler
s390_reset_mcck_handler:
2: .long s390_base_mcck_handler_fn
.section .bss
.globl s390_base_mcck_handler_fn
s390_base_mcck_handler_fn:
.long 0
.previous
.globl reset_pgm_handler
reset_pgm_handler:
.globl s390_base_ext_handler
s390_base_ext_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)
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
......@@ -80,11 +134,17 @@ reset_pgm_handler:
lpsw __LC_PGM_OLD_PSW
1: lpsw disabled_wait_psw-0b(%r13)
.globl s390_reset_pgm_handler
s390_reset_pgm_handler:
.long 0
2: .long s390_base_pgm_handler_fn
disabled_wait_psw:
.align 8
.long 0x000a0000,0x00000000 + reset_pgm_handler
.align 8
.long 0x000a0000,0x00000000 + s390_base_pgm_handler
.section .bss
.globl s390_base_pgm_handler_fn
s390_base_pgm_handler_fn:
.long 0
.previous
#endif /* CONFIG_64BIT */
......@@ -192,7 +192,7 @@ MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>");
#undef cputime_to_timeval
#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;
......
......@@ -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;
......
......@@ -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))
......
......@@ -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;
......
......@@ -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];
......
......@@ -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;
}
......
......@@ -9,6 +9,7 @@
#include <linux/threads.h>
#include <linux/kexec.h>
#include <linux/reboot.h>
void machine_crash_shutdown(struct pt_regs *regs)
{
......
......@@ -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 @@ debug_input_level_fn(debug_info_t * id, struct debug_view *view,
* 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 @@ debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
/*
* 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);
......
/*
* arch/s390/kernel/early.c
*
* Copyright IBM Corp. 2007
* Author(s): Hongjie Yang <hongjie@us.ibm.com>,
* Heiko Carstens <heiko.carstens@de.ibm.com>
*/
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/lockdep.h>
#include <linux/module.h>
#include <linux/pfn.h>
#include <linux/uaccess.h>
#include <asm/lowcore.h>
#include <asm/processor.h>
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/cpcmd.h>
#include <asm/sclp.h>
/*
* Create a Kernel NSS if the SAVESYS= parameter is defined
*/
#define DEFSYS_CMD_SIZE 96
#define SAVESYS_CMD_SIZE 32
char kernel_nss_name[NSS_NAME_SIZE + 1];
#ifdef CONFIG_SHARED_KERNEL
static noinline __init void create_kernel_nss(void)
{
unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
#ifdef CONFIG_BLK_DEV_INITRD
unsigned int sinitrd_pfn, einitrd_pfn;
#endif
int response;
char *savesys_ptr;
char upper_command_line[COMMAND_LINE_SIZE];
char defsys_cmd[DEFSYS_CMD_SIZE];
char savesys_cmd[SAVESYS_CMD_SIZE];
/* Do nothing if we are not running under VM */
if (!MACHINE_IS_VM)
return;
/* Convert COMMAND_LINE to upper case */
for (i = 0; i < strlen(COMMAND_LINE); i++)
upper_command_line[i] = toupper(COMMAND_LINE[i]);
savesys_ptr = strstr(upper_command_line, "SAVESYS=");
if (!savesys_ptr)
return;
savesys_ptr += 8; /* Point to the beginning of the NSS name */
for (i = 0; i < NSS_NAME_SIZE; i++) {
if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0')
break;
kernel_nss_name[i] = savesys_ptr[i];
}
stext_pfn = PFN_DOWN(__pa(&_stext));
eshared_pfn = PFN_DOWN(__pa(&_eshared));
end_pfn = PFN_UP(__pa(&_end));
min_size = end_pfn << 2;
sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1,
eshared_pfn, end_pfn);
#ifdef CONFIG_BLK_DEV_INITRD
if (INITRD_START && INITRD_SIZE) {
sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
min_size = einitrd_pfn << 2;
sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd,
sinitrd_pfn, einitrd_pfn);
}
#endif
sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size);
sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
kernel_nss_name, kernel_nss_name);
__cpcmd(defsys_cmd, NULL, 0, &response);
if (response != 0)
return;
__cpcmd(savesys_cmd, NULL, 0, &response);
if (response != strlen(savesys_cmd))
return;
ipl_flags = IPL_NSS_VALID;
}
#else /* CONFIG_SHARED_KERNEL */
static inline void create_kernel_nss(void) { }
#endif /* CONFIG_SHARED_KERNEL */
/*
* Clear bss memory
*/
static noinline __init void clear_bss_section(void)
{
memset(__bss_start, 0, _end - __bss_start);
}
/*
* Initialize storage key for kernel pages
*/
static noinline __init void init_kernel_storage_key(void)
{
unsigned long end_pfn, init_pfn;
end_pfn = PFN_UP(__pa(&_end));
for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
}
static noinline __init void detect_machine_type(void)
{
struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id));
/* Running under z/VM ? */
if (cpuinfo->cpu_id.version == 0xff)
machine_flags |= 1;
/* Running on a P/390 ? */
if (cpuinfo->cpu_id.machine == 0x7490)
machine_flags |= 4;
}
static noinline __init int memory_fast_detect(void)
{
unsigned long val0 = 0;
unsigned long val1 = 0xc;
int ret = -ENOSYS;
if (ipl_flags & IPL_NSS_VALID)
return -ENOSYS;
asm volatile(
" diag %1,%2,0x260\n"
"0: lhi %0,0\n"
"1:\n"
EX_TABLE(0b,1b)
: "+d" (ret), "+d" (val0), "+d" (val1) : : "cc");
if (ret || val0 != val1)
return -ENOSYS;
memory_chunk[0].size = val0;
return 0;
}
#define ADDR2G (1UL << 31)
static noinline __init unsigned long sclp_memory_detect(void)
{
struct sclp_readinfo_sccb *sccb;
unsigned long long memsize;
sccb = &s390_readinfo_sccb;
if (sccb->header.response_code != 0x10)
return 0;
if (sccb->rnsize)
memsize = sccb->rnsize << 20;
else
memsize = sccb->rnsize2 << 20;
if (sccb->rnmax)
memsize *= sccb->rnmax;
else
memsize *= sccb->rnmax2;
#ifndef CONFIG_64BIT
/*
* Can't deal with more than 2G in 31 bit addressing mode, so
* limit the value in order to avoid strange side effects.
*/
if (memsize > ADDR2G)
memsize = ADDR2G;
#endif
return (unsigned long) memsize;
}
static inline __init unsigned long __tprot(unsigned long addr)
{
int cc = -1;
asm volatile(
" tprot 0(%1),0\n"
"0: ipm %0\n"
" srl %0,28\n"
"1:\n"
EX_TABLE(0b,1b)
: "+d" (cc) : "a" (addr) : "cc");
return (unsigned long)cc;
}
/* Checking memory in 128KB increments. */
#define CHUNK_INCR (1UL << 17)
static noinline __init void find_memory_chunks(unsigned long memsize)
{
unsigned long addr = 0, old_addr = 0;
unsigned long old_cc = CHUNK_READ_WRITE;
unsigned long cc;
int chunk = 0;
while (chunk < MEMORY_CHUNKS) {
cc = __tprot(addr);
while (cc == old_cc) {
addr += CHUNK_INCR;
cc = __tprot(addr);
#ifndef CONFIG_64BIT
if (addr == ADDR2G)
break;
#endif
}
if (old_addr != addr &&
(old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) {
memory_chunk[chunk].addr = old_addr;
memory_chunk[chunk].size = addr - old_addr;
memory_chunk[chunk].type = old_cc;
chunk++;
}
old_addr = addr;
old_cc = cc;
#ifndef CONFIG_64BIT
if (addr == ADDR2G)
break;
#endif
/*
* Finish memory detection at the first hole, unless
* - we reached the hsa -> skip it.
* - we know there must be more.
*/
if (cc == -1UL && !memsize && old_addr != ADDR2G)
break;
if (memsize && addr >= memsize)
break;
}
}
static __init void early_pgm_check_handler(void)
{
unsigned long addr;
const struct exception_table_entry *fixup;
addr = S390_lowcore.program_old_psw.addr;
fixup = search_exception_tables(addr & PSW_ADDR_INSN);
if (!fixup)
disabled_wait(0);
S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
}
static noinline __init void setup_lowcore_early(void)
{
psw_t psw;
psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler;
S390_lowcore.external_new_psw = psw;
psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
S390_lowcore.program_new_psw = psw;
s390_base_pgm_handler_fn = early_pgm_check_handler;
}
/*
* Save ipl parameters, clear bss memory, initialize storage keys
* and create a kernel NSS at startup if the SAVESYS= parm is defined
*/
void __init startup_init(void)
{
unsigned long memsize;
ipl_save_parameters();
clear_bss_section();
init_kernel_storage_key();
lockdep_init();
lockdep_off();
detect_machine_type();
create_kernel_nss();
sort_main_extable();
setup_lowcore_early();
sclp_readinfo_early();
memsize = sclp_memory_detect();
if (memory_fast_detect() < 0)
find_memory_chunks(memsize);
lockdep_on();
}
......@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <asm/types.h>
#include <asm/ebcdic.h>
/*
* ASCII (IBM PC 437) -> EBCDIC 037
......
......@@ -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)
basr %r14,%r14
#
# 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
#
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:
l %r14,.Lstartup_init-.LPG1(%r13)
basr %r14,%r14
#
# 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
......
......@@ -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
......
......@@ -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();
}
/*
* 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);
}
......@@ -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"
"1: la %0,0\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 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
* - 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;
......
......@@ -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>
......
......@@ -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)
{
......
......@@ -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;
......
/*
* arch/s390/kernel/profile.c
*
* Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Thomas Spatzier (tspat@de.ibm.com)
*
*/
#include <linux/proc_fs.h>
#include <linux/profile.h>
static struct proc_dir_entry * root_irq_dir;
void init_irq_proc(void)
{
/* create /proc/irq */
root_irq_dir = proc_mkdir("irq", NULL);
/* create /proc/irq/prof_cpu_mask */
create_prof_cpu_mask(root_irq_dir);
}
......@@ -86,15 +86,13 @@ FixPerRegisters(struct task_struct *task)
per_info->control_regs.bits.storage_alt_space_ctl = 0;
}
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);
}
......
......@@ -125,14 +125,12 @@ 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))
p->handler(code);
}
if (likely(p->code == code))
p->handler(code);
}
irq_exit();
set_irq_regs(old_regs);
......
......@@ -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,8 +550,38 @@ 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);
request_resource(res, &code_resource);
request_resource(res, &data_resource);
if (code_resource.start >= res->start &&
code_resource.start <= res->end &&
code_resource.end > res->end) {
sub_res = alloc_bootmem_low(sizeof(struct resource));
memcpy(sub_res, &code_resource,
sizeof(struct resource));
sub_res->end = res->end;
code_resource.start = res->end + 1;
request_resource(res, sub_res);
}
if (code_resource.start >= res->start &&
code_resource.start <= res->end &&
code_resource.end <= res->end)
request_resource(res, &code_resource);
if (data_resource.start >= res->start &&
data_resource.start <= res->end &&
data_resource.end > res->end) {
sub_res = alloc_bootmem_low(sizeof(struct resource));
memcpy(sub_res, &data_resource,
sizeof(struct resource));
sub_res->end = res->end;
data_resource.start = res->end + 1;
request_resource(res, sub_res);
}
if (data_resource.start >= res->start &&
data_resource.start <= res->end &&
data_resource.end <= res->end)
request_resource(res, &data_resource);
}
}
......@@ -495,16 +611,13 @@ static void __init setup_memory_end(void)
}
if (!memory_end)
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"
......
......@@ -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,
......
......@@ -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;
......
......@@ -11,11 +11,11 @@
#include <linux/stacktrace.h>
#include <linux/kallsyms.h>
static inline unsigned long save_context_stack(struct stack_trace *trace,
unsigned int *skip,
unsigned long sp,
unsigned long low,
unsigned long high)
static unsigned long save_context_stack(struct stack_trace *trace,
unsigned int *skip,
unsigned long sp,
unsigned long low,
unsigned long high)
{
struct stack_frame *sf;
struct pt_regs *regs;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册