mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-11 08:18:47 +00:00
[S390] boot from NSS support
Add support to boot from a named saved segment (NSS). Signed-off-by: Hongjie Yang <hongjie@us.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
1b27829489
commit
fe355b7f1c
@ -51,20 +51,12 @@ startup_continue:
|
|||||||
st %r15,__LC_KERNEL_STACK # set end of kernel stack
|
st %r15,__LC_KERNEL_STACK # set end of kernel stack
|
||||||
ahi %r15,-96
|
ahi %r15,-96
|
||||||
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
|
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
|
||||||
|
#
|
||||||
l %r14,.Lipl_save_parameters-.LPG1(%r13)
|
# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
|
||||||
|
# and create a kernel NSS if the SAVESYS= parm is defined
|
||||||
|
#
|
||||||
|
l %r14,.Lstartup_init-.LPG1(%r13)
|
||||||
basr %r14,%r14
|
basr %r14,%r14
|
||||||
#
|
|
||||||
# clear bss memory
|
|
||||||
#
|
|
||||||
l %r2,.Lbss_bgn-.LPG1(%r13) # start of bss
|
|
||||||
l %r3,.Lbss_end-.LPG1(%r13) # end of bss
|
|
||||||
sr %r3,%r2 # length of bss
|
|
||||||
sr %r4,%r4
|
|
||||||
sr %r5,%r5 # set src,length and pad to zero
|
|
||||||
sr %r0,%r0
|
|
||||||
mvcle %r2,%r4,0 # clear mem
|
|
||||||
jo .-4 # branch back, if not finish
|
|
||||||
|
|
||||||
l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word
|
l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word
|
||||||
.Lservicecall:
|
.Lservicecall:
|
||||||
@ -125,10 +117,10 @@ startup_continue:
|
|||||||
b .Lfchunk-.LPG1(%r13)
|
b .Lfchunk-.LPG1(%r13)
|
||||||
|
|
||||||
.align 4
|
.align 4
|
||||||
.Lipl_save_parameters:
|
|
||||||
.long ipl_save_parameters
|
|
||||||
.Linittu:
|
.Linittu:
|
||||||
.long init_thread_union
|
.long init_thread_union
|
||||||
|
.Lstartup_init:
|
||||||
|
.long startup_init
|
||||||
.Lpmask:
|
.Lpmask:
|
||||||
.byte 0
|
.byte 0
|
||||||
.align 8
|
.align 8
|
||||||
@ -206,20 +198,6 @@ startup_continue:
|
|||||||
jl .Lloop
|
jl .Lloop
|
||||||
.Ldonemem:
|
.Ldonemem:
|
||||||
l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
|
l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
|
||||||
#
|
|
||||||
# find out if we are running under VM
|
|
||||||
#
|
|
||||||
stidp __LC_CPUID # store cpuid
|
|
||||||
tm __LC_CPUID,0xff # running under VM ?
|
|
||||||
bno .Lnovm-.LPG1(%r13)
|
|
||||||
oi 3(%r12),1 # set VM flag
|
|
||||||
.Lnovm:
|
|
||||||
lh %r0,__LC_CPUID+4 # get cpu version
|
|
||||||
chi %r0,0x7490 # running on a P/390 ?
|
|
||||||
bne .Lnop390-.LPG1(%r13)
|
|
||||||
oi 3(%r12),4 # set P/390 flag
|
|
||||||
.Lnop390:
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# find out if we have an IEEE fpu
|
# find out if we have an IEEE fpu
|
||||||
#
|
#
|
||||||
|
@ -58,18 +58,11 @@ startup_continue:
|
|||||||
stg %r15,__LC_KERNEL_STACK # set end of kernel stack
|
stg %r15,__LC_KERNEL_STACK # set end of kernel stack
|
||||||
aghi %r15,-160
|
aghi %r15,-160
|
||||||
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
|
xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
|
||||||
|
|
||||||
brasl %r14,ipl_save_parameters
|
|
||||||
#
|
#
|
||||||
# clear bss memory
|
# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
|
||||||
|
# and create a kernel NSS if the SAVESYS= parm is defined
|
||||||
#
|
#
|
||||||
larl %r2,__bss_start # start of bss segment
|
brasl %r14,startup_init
|
||||||
larl %r3,_end # end of bss segment
|
|
||||||
sgr %r3,%r2 # length of bss
|
|
||||||
sgr %r4,%r4 #
|
|
||||||
sgr %r5,%r5 # set src,length and pad to zero
|
|
||||||
mvcle %r2,%r4,0 # clear mem
|
|
||||||
jo .-4 # branch back, if not finish
|
|
||||||
# set program check new psw mask
|
# set program check new psw mask
|
||||||
mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
|
mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
|
||||||
larl %r1,.Lslowmemdetect # set program check address
|
larl %r1,.Lslowmemdetect # set program check address
|
||||||
@ -78,6 +71,10 @@ startup_continue:
|
|||||||
diag %r0,%r1,0x260 # get memory size of virtual machine
|
diag %r0,%r1,0x260 # get memory size of virtual machine
|
||||||
cgr %r0,%r1 # different? -> old detection routine
|
cgr %r0,%r1 # different? -> old detection routine
|
||||||
jne .Lslowmemdetect
|
jne .Lslowmemdetect
|
||||||
|
larl %r3,ipl_flags
|
||||||
|
llgt %r3,0(%r3)
|
||||||
|
chi %r3,4 # ipled from an kernel NSS
|
||||||
|
je .Lslowmemdetect
|
||||||
aghi %r1,1 # size is one more than end
|
aghi %r1,1 # size is one more than end
|
||||||
larl %r2,memory_chunk
|
larl %r2,memory_chunk
|
||||||
stg %r1,8(%r2) # store size of chunk
|
stg %r1,8(%r2) # store size of chunk
|
||||||
@ -225,19 +222,6 @@ startup_continue:
|
|||||||
.Ldonemem:
|
.Ldonemem:
|
||||||
|
|
||||||
larl %r12,machine_flags
|
larl %r12,machine_flags
|
||||||
#
|
|
||||||
# find out if we are running under VM
|
|
||||||
#
|
|
||||||
stidp __LC_CPUID # store cpuid
|
|
||||||
tm __LC_CPUID,0xff # running under VM ?
|
|
||||||
bno 0f-.LPG1(%r13)
|
|
||||||
oi 7(%r12),1 # set VM flag
|
|
||||||
0: lh %r0,__LC_CPUID+4 # get cpu version
|
|
||||||
chi %r0,0x7490 # running on a P/390 ?
|
|
||||||
bne 1f-.LPG1(%r13)
|
|
||||||
oi 7(%r12),4 # set P/390 flag
|
|
||||||
1:
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# find out if we have the MVPG instruction
|
# find out if we have the MVPG instruction
|
||||||
#
|
#
|
||||||
|
@ -34,12 +34,14 @@ enum ipl_type {
|
|||||||
IPL_TYPE_UNKNOWN = 2,
|
IPL_TYPE_UNKNOWN = 2,
|
||||||
IPL_TYPE_CCW = 4,
|
IPL_TYPE_CCW = 4,
|
||||||
IPL_TYPE_FCP = 8,
|
IPL_TYPE_FCP = 8,
|
||||||
|
IPL_TYPE_NSS = 16,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IPL_NONE_STR "none"
|
#define IPL_NONE_STR "none"
|
||||||
#define IPL_UNKNOWN_STR "unknown"
|
#define IPL_UNKNOWN_STR "unknown"
|
||||||
#define IPL_CCW_STR "ccw"
|
#define IPL_CCW_STR "ccw"
|
||||||
#define IPL_FCP_STR "fcp"
|
#define IPL_FCP_STR "fcp"
|
||||||
|
#define IPL_NSS_STR "nss"
|
||||||
|
|
||||||
static char *ipl_type_str(enum ipl_type type)
|
static char *ipl_type_str(enum ipl_type type)
|
||||||
{
|
{
|
||||||
@ -50,6 +52,8 @@ static char *ipl_type_str(enum ipl_type type)
|
|||||||
return IPL_CCW_STR;
|
return IPL_CCW_STR;
|
||||||
case IPL_TYPE_FCP:
|
case IPL_TYPE_FCP:
|
||||||
return IPL_FCP_STR;
|
return IPL_FCP_STR;
|
||||||
|
case IPL_TYPE_NSS:
|
||||||
|
return IPL_NSS_STR;
|
||||||
case IPL_TYPE_UNKNOWN:
|
case IPL_TYPE_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
return IPL_UNKNOWN_STR;
|
return IPL_UNKNOWN_STR;
|
||||||
@ -64,6 +68,7 @@ enum ipl_method {
|
|||||||
IPL_METHOD_FCP_RO_DIAG,
|
IPL_METHOD_FCP_RO_DIAG,
|
||||||
IPL_METHOD_FCP_RW_DIAG,
|
IPL_METHOD_FCP_RW_DIAG,
|
||||||
IPL_METHOD_FCP_RO_VM,
|
IPL_METHOD_FCP_RO_VM,
|
||||||
|
IPL_METHOD_NSS,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum shutdown_action {
|
enum shutdown_action {
|
||||||
@ -114,11 +119,14 @@ enum diag308_rc {
|
|||||||
static int diag308_set_works = 0;
|
static int diag308_set_works = 0;
|
||||||
|
|
||||||
static int reipl_capabilities = IPL_TYPE_UNKNOWN;
|
static int reipl_capabilities = IPL_TYPE_UNKNOWN;
|
||||||
|
|
||||||
static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
|
static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
|
||||||
static enum ipl_method reipl_method = IPL_METHOD_NONE;
|
static enum ipl_method reipl_method = IPL_METHOD_NONE;
|
||||||
static struct ipl_parameter_block *reipl_block_fcp;
|
static struct ipl_parameter_block *reipl_block_fcp;
|
||||||
static struct ipl_parameter_block *reipl_block_ccw;
|
static struct ipl_parameter_block *reipl_block_ccw;
|
||||||
|
|
||||||
|
static char reipl_nss_name[NSS_NAME_SIZE + 1];
|
||||||
|
|
||||||
static int dump_capabilities = IPL_TYPE_NONE;
|
static int dump_capabilities = IPL_TYPE_NONE;
|
||||||
static enum ipl_type dump_type = IPL_TYPE_NONE;
|
static enum ipl_type dump_type = IPL_TYPE_NONE;
|
||||||
static enum ipl_method dump_method = IPL_METHOD_NONE;
|
static enum ipl_method dump_method = IPL_METHOD_NONE;
|
||||||
@ -173,6 +181,24 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
|
|||||||
sys_##_prefix##_##_name##_show, \
|
sys_##_prefix##_##_name##_show, \
|
||||||
sys_##_prefix##_##_name##_store);
|
sys_##_prefix##_##_name##_store);
|
||||||
|
|
||||||
|
#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
|
||||||
|
static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \
|
||||||
|
char *page) \
|
||||||
|
{ \
|
||||||
|
return sprintf(page, _fmt_out, _value); \
|
||||||
|
} \
|
||||||
|
static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
|
||||||
|
const char *buf, size_t len) \
|
||||||
|
{ \
|
||||||
|
if (sscanf(buf, _fmt_in, _value) != 1) \
|
||||||
|
return -EINVAL; \
|
||||||
|
return len; \
|
||||||
|
} \
|
||||||
|
static struct subsys_attribute sys_##_prefix##_##_name##_attr = \
|
||||||
|
__ATTR(_name,(S_IRUGO | S_IWUSR), \
|
||||||
|
sys_##_prefix##_##_name##_show, \
|
||||||
|
sys_##_prefix##_##_name##_store);
|
||||||
|
|
||||||
static void make_attrs_ro(struct attribute **attrs)
|
static void make_attrs_ro(struct attribute **attrs)
|
||||||
{
|
{
|
||||||
while (*attrs) {
|
while (*attrs) {
|
||||||
@ -189,6 +215,8 @@ static enum ipl_type ipl_get_type(void)
|
|||||||
{
|
{
|
||||||
struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
|
struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
|
||||||
|
|
||||||
|
if (ipl_flags & IPL_NSS_VALID)
|
||||||
|
return IPL_TYPE_NSS;
|
||||||
if (!(ipl_flags & IPL_DEVNO_VALID))
|
if (!(ipl_flags & IPL_DEVNO_VALID))
|
||||||
return IPL_TYPE_UNKNOWN;
|
return IPL_TYPE_UNKNOWN;
|
||||||
if (!(ipl_flags & IPL_PARMBLOCK_VALID))
|
if (!(ipl_flags & IPL_PARMBLOCK_VALID))
|
||||||
@ -324,6 +352,20 @@ static struct attribute_group ipl_ccw_attr_group = {
|
|||||||
.attrs = ipl_ccw_attrs,
|
.attrs = ipl_ccw_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* NSS ipl device attributes */
|
||||||
|
|
||||||
|
DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
|
||||||
|
|
||||||
|
static struct attribute *ipl_nss_attrs[] = {
|
||||||
|
&sys_ipl_type_attr.attr,
|
||||||
|
&sys_ipl_nss_name_attr.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group ipl_nss_attr_group = {
|
||||||
|
.attrs = ipl_nss_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
/* UNKNOWN ipl device attributes */
|
/* UNKNOWN ipl device attributes */
|
||||||
|
|
||||||
static struct attribute *ipl_unknown_attrs[] = {
|
static struct attribute *ipl_unknown_attrs[] = {
|
||||||
@ -432,6 +474,21 @@ static struct attribute_group reipl_ccw_attr_group = {
|
|||||||
.attrs = reipl_ccw_attrs,
|
.attrs = reipl_ccw_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* NSS reipl device attributes */
|
||||||
|
|
||||||
|
DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
|
||||||
|
|
||||||
|
static struct attribute *reipl_nss_attrs[] = {
|
||||||
|
&sys_reipl_nss_name_attr.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group reipl_nss_attr_group = {
|
||||||
|
.name = IPL_NSS_STR,
|
||||||
|
.attrs = reipl_nss_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
/* reipl type */
|
/* reipl type */
|
||||||
|
|
||||||
static int reipl_set_type(enum ipl_type type)
|
static int reipl_set_type(enum ipl_type type)
|
||||||
@ -454,6 +511,9 @@ static int reipl_set_type(enum ipl_type type)
|
|||||||
else
|
else
|
||||||
reipl_method = IPL_METHOD_FCP_RO_DIAG;
|
reipl_method = IPL_METHOD_FCP_RO_DIAG;
|
||||||
break;
|
break;
|
||||||
|
case IPL_TYPE_NSS:
|
||||||
|
reipl_method = IPL_METHOD_NSS;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
reipl_method = IPL_METHOD_NONE;
|
reipl_method = IPL_METHOD_NONE;
|
||||||
}
|
}
|
||||||
@ -475,6 +535,8 @@ static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
|
|||||||
rc = reipl_set_type(IPL_TYPE_CCW);
|
rc = reipl_set_type(IPL_TYPE_CCW);
|
||||||
else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
|
else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
|
||||||
rc = reipl_set_type(IPL_TYPE_FCP);
|
rc = reipl_set_type(IPL_TYPE_FCP);
|
||||||
|
else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
|
||||||
|
rc = reipl_set_type(IPL_TYPE_NSS);
|
||||||
return (rc != 0) ? rc : len;
|
return (rc != 0) ? rc : len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,6 +709,10 @@ void do_reipl(void)
|
|||||||
case IPL_METHOD_FCP_RO_VM:
|
case IPL_METHOD_FCP_RO_VM:
|
||||||
__cpcmd("IPL", NULL, 0, NULL);
|
__cpcmd("IPL", NULL, 0, NULL);
|
||||||
break;
|
break;
|
||||||
|
case IPL_METHOD_NSS:
|
||||||
|
sprintf(buf, "IPL %s", reipl_nss_name);
|
||||||
|
__cpcmd(buf, NULL, 0, NULL);
|
||||||
|
break;
|
||||||
case IPL_METHOD_NONE:
|
case IPL_METHOD_NONE:
|
||||||
default:
|
default:
|
||||||
if (MACHINE_IS_VM)
|
if (MACHINE_IS_VM)
|
||||||
@ -733,6 +799,10 @@ static int __init ipl_init(void)
|
|||||||
case IPL_TYPE_FCP:
|
case IPL_TYPE_FCP:
|
||||||
rc = ipl_register_fcp_files();
|
rc = ipl_register_fcp_files();
|
||||||
break;
|
break;
|
||||||
|
case IPL_TYPE_NSS:
|
||||||
|
rc = sysfs_create_group(&ipl_subsys.kset.kobj,
|
||||||
|
&ipl_nss_attr_group);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
rc = sysfs_create_group(&ipl_subsys.kset.kobj,
|
rc = sysfs_create_group(&ipl_subsys.kset.kobj,
|
||||||
&ipl_unknown_attr_group);
|
&ipl_unknown_attr_group);
|
||||||
@ -755,6 +825,20 @@ static void __init reipl_probe(void)
|
|||||||
free_page((unsigned long)buffer);
|
free_page((unsigned long)buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __init reipl_nss_init(void)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!MACHINE_IS_VM)
|
||||||
|
return 0;
|
||||||
|
rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
|
||||||
|
reipl_capabilities |= IPL_TYPE_NSS;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init reipl_ccw_init(void)
|
static int __init reipl_ccw_init(void)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@ -835,6 +919,9 @@ static int __init reipl_init(void)
|
|||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
rc = reipl_fcp_init();
|
rc = reipl_fcp_init();
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
rc = reipl_nss_init();
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
rc = reipl_set_type(ipl_get_type());
|
rc = reipl_set_type(ipl_get_type());
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/notifier.h>
|
#include <linux/notifier.h>
|
||||||
#include <linux/pfn.h>
|
#include <linux/pfn.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/reboot.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
@ -50,6 +51,7 @@
|
|||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
#include <asm/ptrace.h>
|
#include <asm/ptrace.h>
|
||||||
#include <asm/sections.h>
|
#include <asm/sections.h>
|
||||||
|
#include <asm/ebcdic.h>
|
||||||
#include <asm/compat.h>
|
#include <asm/compat.h>
|
||||||
|
|
||||||
long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
|
long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
|
||||||
@ -282,6 +284,140 @@ static void __init conmode_default(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a Kernel NSS if the SAVESYS= parameter is defined
|
||||||
|
*/
|
||||||
|
#define DEFSYS_CMD_SIZE 96
|
||||||
|
#define SAVESYS_CMD_SIZE 32
|
||||||
|
|
||||||
|
extern int _eshared;
|
||||||
|
char kernel_nss_name[NSS_NAME_SIZE + 1];
|
||||||
|
|
||||||
|
#ifdef CONFIG_SHARED_KERNEL
|
||||||
|
static __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 __init void clear_bss_section(void)
|
||||||
|
{
|
||||||
|
memset(__bss_start, 0, _end - __bss_start);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize storage key for kernel pages
|
||||||
|
*/
|
||||||
|
static __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 __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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
ipl_save_parameters();
|
||||||
|
clear_bss_section();
|
||||||
|
init_kernel_storage_key();
|
||||||
|
lockdep_init();
|
||||||
|
detect_machine_type();
|
||||||
|
create_kernel_nss();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
void (*_machine_restart)(char *command) = machine_restart_smp;
|
void (*_machine_restart)(char *command) = machine_restart_smp;
|
||||||
void (*_machine_halt)(void) = machine_halt_smp;
|
void (*_machine_halt)(void) = machine_halt_smp;
|
||||||
@ -523,7 +659,7 @@ setup_lowcore(void)
|
|||||||
static void __init
|
static void __init
|
||||||
setup_resources(void)
|
setup_resources(void)
|
||||||
{
|
{
|
||||||
struct resource *res;
|
struct resource *res, *sub_res;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
code_resource.start = (unsigned long) &_text;
|
code_resource.start = (unsigned long) &_text;
|
||||||
@ -548,7 +684,37 @@ setup_resources(void)
|
|||||||
res->start = memory_chunk[i].addr;
|
res->start = memory_chunk[i].addr;
|
||||||
res->end = memory_chunk[i].addr + memory_chunk[i].size - 1;
|
res->end = memory_chunk[i].addr + memory_chunk[i].size - 1;
|
||||||
request_resource(&iomem_resource, res);
|
request_resource(&iomem_resource, res);
|
||||||
|
|
||||||
|
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);
|
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);
|
request_resource(res, &data_resource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -585,7 +751,7 @@ static void __init
|
|||||||
setup_memory(void)
|
setup_memory(void)
|
||||||
{
|
{
|
||||||
unsigned long bootmap_size;
|
unsigned long bootmap_size;
|
||||||
unsigned long start_pfn, end_pfn, init_pfn;
|
unsigned long start_pfn, end_pfn;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -595,10 +761,6 @@ setup_memory(void)
|
|||||||
start_pfn = PFN_UP(__pa(&_end));
|
start_pfn = PFN_UP(__pa(&_end));
|
||||||
end_pfn = max_pfn = PFN_DOWN(memory_end);
|
end_pfn = max_pfn = PFN_DOWN(memory_end);
|
||||||
|
|
||||||
/* Initialize storage key for kernel pages */
|
|
||||||
for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++)
|
|
||||||
page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
|
|
||||||
|
|
||||||
#ifdef CONFIG_BLK_DEV_INITRD
|
#ifdef CONFIG_BLK_DEV_INITRD
|
||||||
/*
|
/*
|
||||||
* Move the initrd in case the bitmap of the bootmem allocater
|
* Move the initrd in case the bitmap of the bootmem allocater
|
||||||
|
@ -31,11 +31,6 @@ SECTIONS
|
|||||||
|
|
||||||
_etext = .; /* End of text section */
|
_etext = .; /* End of text section */
|
||||||
|
|
||||||
. = ALIGN(16); /* Exception table */
|
|
||||||
__start___ex_table = .;
|
|
||||||
__ex_table : { *(__ex_table) }
|
|
||||||
__stop___ex_table = .;
|
|
||||||
|
|
||||||
RODATA
|
RODATA
|
||||||
|
|
||||||
#ifdef CONFIG_SHARED_KERNEL
|
#ifdef CONFIG_SHARED_KERNEL
|
||||||
@ -44,6 +39,11 @@ SECTIONS
|
|||||||
_eshared = .; /* End of shareable data */
|
_eshared = .; /* End of shareable data */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
. = ALIGN(16); /* Exception table */
|
||||||
|
__start___ex_table = .;
|
||||||
|
__ex_table : { *(__ex_table) }
|
||||||
|
__stop___ex_table = .;
|
||||||
|
|
||||||
.data : { /* Data */
|
.data : { /* Data */
|
||||||
*(.data)
|
*(.data)
|
||||||
CONSTRUCTORS
|
CONSTRUCTORS
|
||||||
|
@ -156,13 +156,19 @@ struct ipl_parameter_block {
|
|||||||
extern u32 ipl_flags;
|
extern u32 ipl_flags;
|
||||||
extern u16 ipl_devno;
|
extern u16 ipl_devno;
|
||||||
|
|
||||||
void do_reipl(void);
|
extern void do_reipl(void);
|
||||||
|
extern void ipl_save_parameters(void);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
IPL_DEVNO_VALID = 1,
|
IPL_DEVNO_VALID = 1,
|
||||||
IPL_PARMBLOCK_VALID = 2,
|
IPL_PARMBLOCK_VALID = 2,
|
||||||
|
IPL_NSS_VALID = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define NSS_NAME_SIZE 8
|
||||||
|
|
||||||
|
extern char kernel_nss_name[];
|
||||||
|
|
||||||
#define IPL_PARMBLOCK_START ((struct ipl_parameter_block *) \
|
#define IPL_PARMBLOCK_START ((struct ipl_parameter_block *) \
|
||||||
IPL_PARMBLOCK_ORIGIN)
|
IPL_PARMBLOCK_ORIGIN)
|
||||||
#define IPL_PARMBLOCK_SIZE (IPL_PARMBLOCK_START->hdr.len)
|
#define IPL_PARMBLOCK_SIZE (IPL_PARMBLOCK_START->hdr.len)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user