diff options
| author | Hongjie Yang <hongjie@us.ibm.com> | 2007-02-05 15:18:24 -0500 |
|---|---|---|
| committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-02-05 15:18:24 -0500 |
| commit | fe355b7f1c7400cbb71762a1237461be03f88265 (patch) | |
| tree | 8ef581c8ff0889a200bae88a4961395bcb80aec4 | |
| parent | 1b2782948997cf5a0d1747de13d43ba7dfa7c543 (diff) | |
[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>
| -rw-r--r-- | arch/s390/kernel/head31.S | 34 | ||||
| -rw-r--r-- | arch/s390/kernel/head64.S | 30 | ||||
| -rw-r--r-- | arch/s390/kernel/ipl.c | 87 | ||||
| -rw-r--r-- | arch/s390/kernel/setup.c | 178 | ||||
| -rw-r--r-- | arch/s390/kernel/vmlinux.lds.S | 10 | ||||
| -rw-r--r-- | include/asm-s390/setup.h | 8 |
6 files changed, 282 insertions, 65 deletions
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index eca507050e47..b3dcdcdc80c0 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S | |||
| @@ -51,20 +51,12 @@ startup_continue: | |||
| 51 | st %r15,__LC_KERNEL_STACK # set end of kernel stack | 51 | st %r15,__LC_KERNEL_STACK # set end of kernel stack |
| 52 | ahi %r15,-96 | 52 | ahi %r15,-96 |
| 53 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain | 53 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain |
| 54 | |||
| 55 | l %r14,.Lipl_save_parameters-.LPG1(%r13) | ||
| 56 | basr %r14,%r14 | ||
| 57 | # | 54 | # |
| 58 | # clear bss memory | 55 | # Save ipl parameters, clear bss memory, initialize storage key for kernel pages, |
| 56 | # and create a kernel NSS if the SAVESYS= parm is defined | ||
| 59 | # | 57 | # |
| 60 | l %r2,.Lbss_bgn-.LPG1(%r13) # start of bss | 58 | l %r14,.Lstartup_init-.LPG1(%r13) |
| 61 | l %r3,.Lbss_end-.LPG1(%r13) # end of bss | 59 | basr %r14,%r14 |
| 62 | sr %r3,%r2 # length of bss | ||
| 63 | sr %r4,%r4 | ||
| 64 | sr %r5,%r5 # set src,length and pad to zero | ||
| 65 | sr %r0,%r0 | ||
| 66 | mvcle %r2,%r4,0 # clear mem | ||
| 67 | jo .-4 # branch back, if not finish | ||
| 68 | 60 | ||
| 69 | l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word | 61 | l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word |
| 70 | .Lservicecall: | 62 | .Lservicecall: |
| @@ -125,10 +117,10 @@ startup_continue: | |||
| 125 | b .Lfchunk-.LPG1(%r13) | 117 | b .Lfchunk-.LPG1(%r13) |
| 126 | 118 | ||
| 127 | .align 4 | 119 | .align 4 |
| 128 | .Lipl_save_parameters: | ||
| 129 | .long ipl_save_parameters | ||
| 130 | .Linittu: | 120 | .Linittu: |
| 131 | .long init_thread_union | 121 | .long init_thread_union |
| 122 | .Lstartup_init: | ||
| 123 | .long startup_init | ||
| 132 | .Lpmask: | 124 | .Lpmask: |
| 133 | .byte 0 | 125 | .byte 0 |
| 134 | .align 8 | 126 | .align 8 |
| @@ -207,20 +199,6 @@ startup_continue: | |||
| 207 | .Ldonemem: | 199 | .Ldonemem: |
| 208 | l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags | 200 | l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags |
| 209 | # | 201 | # |
| 210 | # find out if we are running under VM | ||
| 211 | # | ||
| 212 | stidp __LC_CPUID # store cpuid | ||
| 213 | tm __LC_CPUID,0xff # running under VM ? | ||
| 214 | bno .Lnovm-.LPG1(%r13) | ||
| 215 | oi 3(%r12),1 # set VM flag | ||
| 216 | .Lnovm: | ||
| 217 | lh %r0,__LC_CPUID+4 # get cpu version | ||
| 218 | chi %r0,0x7490 # running on a P/390 ? | ||
| 219 | bne .Lnop390-.LPG1(%r13) | ||
| 220 | oi 3(%r12),4 # set P/390 flag | ||
| 221 | .Lnop390: | ||
| 222 | |||
| 223 | # | ||
| 224 | # find out if we have an IEEE fpu | 202 | # find out if we have an IEEE fpu |
| 225 | # | 203 | # |
| 226 | mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13) | 204 | mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13) |
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index e940e802cb40..030a1c95f47c 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S | |||
| @@ -58,18 +58,11 @@ startup_continue: | |||
| 58 | stg %r15,__LC_KERNEL_STACK # set end of kernel stack | 58 | stg %r15,__LC_KERNEL_STACK # set end of kernel stack |
| 59 | aghi %r15,-160 | 59 | aghi %r15,-160 |
| 60 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain | 60 | xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain |
| 61 | |||
| 62 | brasl %r14,ipl_save_parameters | ||
| 63 | # | 61 | # |
| 64 | # clear bss memory | 62 | # Save ipl parameters, clear bss memory, initialize storage key for kernel pages, |
| 63 | # and create a kernel NSS if the SAVESYS= parm is defined | ||
| 65 | # | 64 | # |
| 66 | larl %r2,__bss_start # start of bss segment | 65 | brasl %r14,startup_init |
| 67 | larl %r3,_end # end of bss segment | ||
| 68 | sgr %r3,%r2 # length of bss | ||
| 69 | sgr %r4,%r4 # | ||
| 70 | sgr %r5,%r5 # set src,length and pad to zero | ||
| 71 | mvcle %r2,%r4,0 # clear mem | ||
| 72 | jo .-4 # branch back, if not finish | ||
| 73 | # set program check new psw mask | 66 | # set program check new psw mask |
| 74 | mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) | 67 | mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) |
| 75 | larl %r1,.Lslowmemdetect # set program check address | 68 | larl %r1,.Lslowmemdetect # set program check address |
| @@ -78,6 +71,10 @@ startup_continue: | |||
| 78 | diag %r0,%r1,0x260 # get memory size of virtual machine | 71 | diag %r0,%r1,0x260 # get memory size of virtual machine |
| 79 | cgr %r0,%r1 # different? -> old detection routine | 72 | cgr %r0,%r1 # different? -> old detection routine |
| 80 | jne .Lslowmemdetect | 73 | jne .Lslowmemdetect |
| 74 | larl %r3,ipl_flags | ||
| 75 | llgt %r3,0(%r3) | ||
| 76 | chi %r3,4 # ipled from an kernel NSS | ||
| 77 | je .Lslowmemdetect | ||
| 81 | aghi %r1,1 # size is one more than end | 78 | aghi %r1,1 # size is one more than end |
| 82 | larl %r2,memory_chunk | 79 | larl %r2,memory_chunk |
| 83 | stg %r1,8(%r2) # store size of chunk | 80 | stg %r1,8(%r2) # store size of chunk |
| @@ -226,19 +223,6 @@ startup_continue: | |||
| 226 | 223 | ||
| 227 | larl %r12,machine_flags | 224 | larl %r12,machine_flags |
| 228 | # | 225 | # |
| 229 | # find out if we are running under VM | ||
| 230 | # | ||
| 231 | stidp __LC_CPUID # store cpuid | ||
| 232 | tm __LC_CPUID,0xff # running under VM ? | ||
| 233 | bno 0f-.LPG1(%r13) | ||
| 234 | oi 7(%r12),1 # set VM flag | ||
| 235 | 0: lh %r0,__LC_CPUID+4 # get cpu version | ||
| 236 | chi %r0,0x7490 # running on a P/390 ? | ||
| 237 | bne 1f-.LPG1(%r13) | ||
| 238 | oi 7(%r12),4 # set P/390 flag | ||
| 239 | 1: | ||
| 240 | |||
| 241 | # | ||
| 242 | # find out if we have the MVPG instruction | 226 | # find out if we have the MVPG instruction |
| 243 | # | 227 | # |
| 244 | la %r1,0f-.LPG1(%r13) # set program check address | 228 | la %r1,0f-.LPG1(%r13) # set program check address |
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 2c91226e1d40..13eacce62011 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
| @@ -34,12 +34,14 @@ enum ipl_type { | |||
| 34 | IPL_TYPE_UNKNOWN = 2, | 34 | IPL_TYPE_UNKNOWN = 2, |
| 35 | IPL_TYPE_CCW = 4, | 35 | IPL_TYPE_CCW = 4, |
| 36 | IPL_TYPE_FCP = 8, | 36 | IPL_TYPE_FCP = 8, |
| 37 | IPL_TYPE_NSS = 16, | ||
| 37 | }; | 38 | }; |
| 38 | 39 | ||
| 39 | #define IPL_NONE_STR "none" | 40 | #define IPL_NONE_STR "none" |
| 40 | #define IPL_UNKNOWN_STR "unknown" | 41 | #define IPL_UNKNOWN_STR "unknown" |
| 41 | #define IPL_CCW_STR "ccw" | 42 | #define IPL_CCW_STR "ccw" |
| 42 | #define IPL_FCP_STR "fcp" | 43 | #define IPL_FCP_STR "fcp" |
| 44 | #define IPL_NSS_STR "nss" | ||
| 43 | 45 | ||
| 44 | static char *ipl_type_str(enum ipl_type type) | 46 | static char *ipl_type_str(enum ipl_type type) |
| 45 | { | 47 | { |
| @@ -50,6 +52,8 @@ static char *ipl_type_str(enum ipl_type type) | |||
| 50 | return IPL_CCW_STR; | 52 | return IPL_CCW_STR; |
| 51 | case IPL_TYPE_FCP: | 53 | case IPL_TYPE_FCP: |
| 52 | return IPL_FCP_STR; | 54 | return IPL_FCP_STR; |
| 55 | case IPL_TYPE_NSS: | ||
| 56 | return IPL_NSS_STR; | ||
| 53 | case IPL_TYPE_UNKNOWN: | 57 | case IPL_TYPE_UNKNOWN: |
| 54 | default: | 58 | default: |
| 55 | return IPL_UNKNOWN_STR; | 59 | return IPL_UNKNOWN_STR; |
| @@ -64,6 +68,7 @@ enum ipl_method { | |||
| 64 | IPL_METHOD_FCP_RO_DIAG, | 68 | IPL_METHOD_FCP_RO_DIAG, |
| 65 | IPL_METHOD_FCP_RW_DIAG, | 69 | IPL_METHOD_FCP_RW_DIAG, |
| 66 | IPL_METHOD_FCP_RO_VM, | 70 | IPL_METHOD_FCP_RO_VM, |
| 71 | IPL_METHOD_NSS, | ||
| 67 | }; | 72 | }; |
| 68 | 73 | ||
| 69 | enum shutdown_action { | 74 | enum shutdown_action { |
| @@ -114,11 +119,14 @@ enum diag308_rc { | |||
| 114 | static int diag308_set_works = 0; | 119 | static int diag308_set_works = 0; |
| 115 | 120 | ||
| 116 | static int reipl_capabilities = IPL_TYPE_UNKNOWN; | 121 | static int reipl_capabilities = IPL_TYPE_UNKNOWN; |
| 122 | |||
| 117 | static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN; | 123 | static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN; |
| 118 | static enum ipl_method reipl_method = IPL_METHOD_NONE; | 124 | static enum ipl_method reipl_method = IPL_METHOD_NONE; |
| 119 | static struct ipl_parameter_block *reipl_block_fcp; | 125 | static struct ipl_parameter_block *reipl_block_fcp; |
| 120 | static struct ipl_parameter_block *reipl_block_ccw; | 126 | static struct ipl_parameter_block *reipl_block_ccw; |
| 121 | 127 | ||
| 128 | static char reipl_nss_name[NSS_NAME_SIZE + 1]; | ||
| 129 | |||
| 122 | static int dump_capabilities = IPL_TYPE_NONE; | 130 | static int dump_capabilities = IPL_TYPE_NONE; |
| 123 | static enum ipl_type dump_type = IPL_TYPE_NONE; | 131 | static enum ipl_type dump_type = IPL_TYPE_NONE; |
| 124 | static enum ipl_method dump_method = IPL_METHOD_NONE; | 132 | static enum ipl_method dump_method = IPL_METHOD_NONE; |
| @@ -173,6 +181,24 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ | |||
| 173 | sys_##_prefix##_##_name##_show, \ | 181 | sys_##_prefix##_##_name##_show, \ |
| 174 | sys_##_prefix##_##_name##_store); | 182 | sys_##_prefix##_##_name##_store); |
| 175 | 183 | ||
| 184 | #define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\ | ||
| 185 | static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys, \ | ||
| 186 | char *page) \ | ||
| 187 | { \ | ||
| 188 | return sprintf(page, _fmt_out, _value); \ | ||
| 189 | } \ | ||
| 190 | static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\ | ||
| 191 | const char *buf, size_t len) \ | ||
| 192 | { \ | ||
| 193 | if (sscanf(buf, _fmt_in, _value) != 1) \ | ||
| 194 | return -EINVAL; \ | ||
| 195 | return len; \ | ||
| 196 | } \ | ||
| 197 | static struct subsys_attribute sys_##_prefix##_##_name##_attr = \ | ||
| 198 | __ATTR(_name,(S_IRUGO | S_IWUSR), \ | ||
| 199 | sys_##_prefix##_##_name##_show, \ | ||
| 200 | sys_##_prefix##_##_name##_store); | ||
| 201 | |||
| 176 | static void make_attrs_ro(struct attribute **attrs) | 202 | static void make_attrs_ro(struct attribute **attrs) |
| 177 | { | 203 | { |
| 178 | while (*attrs) { | 204 | while (*attrs) { |
| @@ -189,6 +215,8 @@ static enum ipl_type ipl_get_type(void) | |||
| 189 | { | 215 | { |
| 190 | struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; | 216 | struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START; |
| 191 | 217 | ||
| 218 | if (ipl_flags & IPL_NSS_VALID) | ||
| 219 | return IPL_TYPE_NSS; | ||
| 192 | if (!(ipl_flags & IPL_DEVNO_VALID)) | 220 | if (!(ipl_flags & IPL_DEVNO_VALID)) |
| 193 | return IPL_TYPE_UNKNOWN; | 221 | return IPL_TYPE_UNKNOWN; |
| 194 | if (!(ipl_flags & IPL_PARMBLOCK_VALID)) | 222 | if (!(ipl_flags & IPL_PARMBLOCK_VALID)) |
| @@ -324,6 +352,20 @@ static struct attribute_group ipl_ccw_attr_group = { | |||
| 324 | .attrs = ipl_ccw_attrs, | 352 | .attrs = ipl_ccw_attrs, |
| 325 | }; | 353 | }; |
| 326 | 354 | ||
| 355 | /* NSS ipl device attributes */ | ||
| 356 | |||
| 357 | DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name); | ||
| 358 | |||
| 359 | static struct attribute *ipl_nss_attrs[] = { | ||
| 360 | &sys_ipl_type_attr.attr, | ||
| 361 | &sys_ipl_nss_name_attr.attr, | ||
| 362 | NULL, | ||
| 363 | }; | ||
| 364 | |||
| 365 | static struct attribute_group ipl_nss_attr_group = { | ||
| 366 | .attrs = ipl_nss_attrs, | ||
| 367 | }; | ||
| 368 | |||
| 327 | /* UNKNOWN ipl device attributes */ | 369 | /* UNKNOWN ipl device attributes */ |
| 328 | 370 | ||
| 329 | static struct attribute *ipl_unknown_attrs[] = { | 371 | static struct attribute *ipl_unknown_attrs[] = { |
| @@ -432,6 +474,21 @@ static struct attribute_group reipl_ccw_attr_group = { | |||
| 432 | .attrs = reipl_ccw_attrs, | 474 | .attrs = reipl_ccw_attrs, |
| 433 | }; | 475 | }; |
| 434 | 476 | ||
| 477 | |||
| 478 | /* NSS reipl device attributes */ | ||
| 479 | |||
| 480 | DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name); | ||
| 481 | |||
| 482 | static struct attribute *reipl_nss_attrs[] = { | ||
| 483 | &sys_reipl_nss_name_attr.attr, | ||
| 484 | NULL, | ||
| 485 | }; | ||
| 486 | |||
| 487 | static struct attribute_group reipl_nss_attr_group = { | ||
| 488 | .name = IPL_NSS_STR, | ||
| 489 | .attrs = reipl_nss_attrs, | ||
| 490 | }; | ||
| 491 | |||
| 435 | /* reipl type */ | 492 | /* reipl type */ |
| 436 | 493 | ||
| 437 | static int reipl_set_type(enum ipl_type type) | 494 | static int reipl_set_type(enum ipl_type type) |
| @@ -454,6 +511,9 @@ static int reipl_set_type(enum ipl_type type) | |||
| 454 | else | 511 | else |
| 455 | reipl_method = IPL_METHOD_FCP_RO_DIAG; | 512 | reipl_method = IPL_METHOD_FCP_RO_DIAG; |
| 456 | break; | 513 | break; |
| 514 | case IPL_TYPE_NSS: | ||
| 515 | reipl_method = IPL_METHOD_NSS; | ||
| 516 | break; | ||
| 457 | default: | 517 | default: |
| 458 | reipl_method = IPL_METHOD_NONE; | 518 | reipl_method = IPL_METHOD_NONE; |
| 459 | } | 519 | } |
| @@ -475,6 +535,8 @@ static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf, | |||
| 475 | rc = reipl_set_type(IPL_TYPE_CCW); | 535 | rc = reipl_set_type(IPL_TYPE_CCW); |
| 476 | else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0) | 536 | else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0) |
| 477 | rc = reipl_set_type(IPL_TYPE_FCP); | 537 | rc = reipl_set_type(IPL_TYPE_FCP); |
| 538 | else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0) | ||
| 539 | rc = reipl_set_type(IPL_TYPE_NSS); | ||
| 478 | return (rc != 0) ? rc : len; | 540 | return (rc != 0) ? rc : len; |
| 479 | } | 541 | } |
| 480 | 542 | ||
| @@ -647,6 +709,10 @@ void do_reipl(void) | |||
| 647 | case IPL_METHOD_FCP_RO_VM: | 709 | case IPL_METHOD_FCP_RO_VM: |
| 648 | __cpcmd("IPL", NULL, 0, NULL); | 710 | __cpcmd("IPL", NULL, 0, NULL); |
| 649 | break; | 711 | break; |
| 712 | case IPL_METHOD_NSS: | ||
| 713 | sprintf(buf, "IPL %s", reipl_nss_name); | ||
| 714 | __cpcmd(buf, NULL, 0, NULL); | ||
| 715 | break; | ||
| 650 | case IPL_METHOD_NONE: | 716 | case IPL_METHOD_NONE: |
| 651 | default: | 717 | default: |
| 652 | if (MACHINE_IS_VM) | 718 | if (MACHINE_IS_VM) |
| @@ -733,6 +799,10 @@ static int __init ipl_init(void) | |||
| 733 | case IPL_TYPE_FCP: | 799 | case IPL_TYPE_FCP: |
| 734 | rc = ipl_register_fcp_files(); | 800 | rc = ipl_register_fcp_files(); |
| 735 | break; | 801 | break; |
| 802 | case IPL_TYPE_NSS: | ||
| 803 | rc = sysfs_create_group(&ipl_subsys.kset.kobj, | ||
| 804 | &ipl_nss_attr_group); | ||
| 805 | break; | ||
| 736 | default: | 806 | default: |
| 737 | rc = sysfs_create_group(&ipl_subsys.kset.kobj, | 807 | rc = sysfs_create_group(&ipl_subsys.kset.kobj, |
| 738 | &ipl_unknown_attr_group); | 808 | &ipl_unknown_attr_group); |
| @@ -755,6 +825,20 @@ static void __init reipl_probe(void) | |||
| 755 | free_page((unsigned long)buffer); | 825 | free_page((unsigned long)buffer); |
| 756 | } | 826 | } |
| 757 | 827 | ||
| 828 | static int __init reipl_nss_init(void) | ||
| 829 | { | ||
| 830 | int rc; | ||
| 831 | |||
| 832 | if (!MACHINE_IS_VM) | ||
| 833 | return 0; | ||
| 834 | rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group); | ||
| 835 | if (rc) | ||
| 836 | return rc; | ||
| 837 | strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1); | ||
| 838 | reipl_capabilities |= IPL_TYPE_NSS; | ||
| 839 | return 0; | ||
| 840 | } | ||
| 841 | |||
| 758 | static int __init reipl_ccw_init(void) | 842 | static int __init reipl_ccw_init(void) |
| 759 | { | 843 | { |
| 760 | int rc; | 844 | int rc; |
| @@ -837,6 +921,9 @@ static int __init reipl_init(void) | |||
| 837 | rc = reipl_fcp_init(); | 921 | rc = reipl_fcp_init(); |
| 838 | if (rc) | 922 | if (rc) |
| 839 | return rc; | 923 | return rc; |
| 924 | rc = reipl_nss_init(); | ||
| 925 | if (rc) | ||
| 926 | return rc; | ||
| 840 | rc = reipl_set_type(ipl_get_type()); | 927 | rc = reipl_set_type(ipl_get_type()); |
| 841 | if (rc) | 928 | if (rc) |
| 842 | return rc; | 929 | return rc; |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index b1b9a931237d..2569aafcc543 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/device.h> | 38 | #include <linux/device.h> |
| 39 | #include <linux/notifier.h> | 39 | #include <linux/notifier.h> |
| 40 | #include <linux/pfn.h> | 40 | #include <linux/pfn.h> |
| 41 | #include <linux/ctype.h> | ||
| 41 | #include <linux/reboot.h> | 42 | #include <linux/reboot.h> |
| 42 | 43 | ||
| 43 | #include <asm/uaccess.h> | 44 | #include <asm/uaccess.h> |
| @@ -50,6 +51,7 @@ | |||
| 50 | #include <asm/page.h> | 51 | #include <asm/page.h> |
| 51 | #include <asm/ptrace.h> | 52 | #include <asm/ptrace.h> |
| 52 | #include <asm/sections.h> | 53 | #include <asm/sections.h> |
| 54 | #include <asm/ebcdic.h> | ||
| 53 | #include <asm/compat.h> | 55 | #include <asm/compat.h> |
| 54 | 56 | ||
| 55 | long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | | 57 | long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | |
| @@ -282,6 +284,140 @@ static void __init conmode_default(void) | |||
| 282 | } | 284 | } |
| 283 | } | 285 | } |
| 284 | 286 | ||
| 287 | /* | ||
| 288 | * Create a Kernel NSS if the SAVESYS= parameter is defined | ||
| 289 | */ | ||
| 290 | #define DEFSYS_CMD_SIZE 96 | ||
| 291 | #define SAVESYS_CMD_SIZE 32 | ||
| 292 | |||
| 293 | extern int _eshared; | ||
| 294 | char kernel_nss_name[NSS_NAME_SIZE + 1]; | ||
| 295 | |||
| 296 | #ifdef CONFIG_SHARED_KERNEL | ||
| 297 | static __init void create_kernel_nss(void) | ||
| 298 | { | ||
| 299 | unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; | ||
| 300 | #ifdef CONFIG_BLK_DEV_INITRD | ||
| 301 | unsigned int sinitrd_pfn, einitrd_pfn; | ||
| 302 | #endif | ||
| 303 | int response; | ||
| 304 | char *savesys_ptr; | ||
| 305 | char upper_command_line[COMMAND_LINE_SIZE]; | ||
| 306 | char defsys_cmd[DEFSYS_CMD_SIZE]; | ||
| 307 | char savesys_cmd[SAVESYS_CMD_SIZE]; | ||
| 308 | |||
| 309 | /* Do nothing if we are not running under VM */ | ||
| 310 | if (!MACHINE_IS_VM) | ||
| 311 | return; | ||
| 312 | |||
| 313 | /* Convert COMMAND_LINE to upper case */ | ||
| 314 | for (i = 0; i < strlen(COMMAND_LINE); i++) | ||
| 315 | upper_command_line[i] = toupper(COMMAND_LINE[i]); | ||
| 316 | |||
| 317 | savesys_ptr = strstr(upper_command_line, "SAVESYS="); | ||
| 318 | |||
| 319 | if (!savesys_ptr) | ||
| 320 | return; | ||
| 321 | |||
| 322 | savesys_ptr += 8; /* Point to the beginning of the NSS name */ | ||
| 323 | for (i = 0; i < NSS_NAME_SIZE; i++) { | ||
| 324 | if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0') | ||
| 325 | break; | ||
| 326 | kernel_nss_name[i] = savesys_ptr[i]; | ||
| 327 | } | ||
| 328 | |||
| 329 | stext_pfn = PFN_DOWN(__pa(&_stext)); | ||
| 330 | eshared_pfn = PFN_DOWN(__pa(&_eshared)); | ||
| 331 | end_pfn = PFN_UP(__pa(&_end)); | ||
| 332 | min_size = end_pfn << 2; | ||
| 333 | |||
| 334 | sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X", | ||
| 335 | kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1, | ||
| 336 | eshared_pfn, end_pfn); | ||
| 337 | |||
| 338 | #ifdef CONFIG_BLK_DEV_INITRD | ||
| 339 | if (INITRD_START && INITRD_SIZE) { | ||
| 340 | sinitrd_pfn = PFN_DOWN(__pa(INITRD_START)); | ||
| 341 | einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE)); | ||
| 342 | min_size = einitrd_pfn << 2; | ||
| 343 | sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd, | ||
| 344 | sinitrd_pfn, einitrd_pfn); | ||
| 345 | } | ||
| 346 | #endif | ||
| 347 | |||
| 348 | sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size); | ||
| 349 | sprintf(savesys_cmd, "SAVESYS %s \n IPL %s", | ||
| 350 | kernel_nss_name, kernel_nss_name); | ||
| 351 | |||
| 352 | __cpcmd(defsys_cmd, NULL, 0, &response); | ||
| 353 | |||
| 354 | if (response != 0) | ||
| 355 | return; | ||
| 356 | |||
| 357 | __cpcmd(savesys_cmd, NULL, 0, &response); | ||
| 358 | |||
| 359 | if (response != strlen(savesys_cmd)) | ||
| 360 | return; | ||
| 361 | |||
| 362 | ipl_flags = IPL_NSS_VALID; | ||
| 363 | } | ||
| 364 | |||
| 365 | #else /* CONFIG_SHARED_KERNEL */ | ||
| 366 | |||
| 367 | static inline void create_kernel_nss(void) { } | ||
| 368 | |||
| 369 | #endif /* CONFIG_SHARED_KERNEL */ | ||
| 370 | |||
| 371 | /* | ||
| 372 | * Clear bss memory | ||
| 373 | */ | ||
| 374 | static __init void clear_bss_section(void) | ||
| 375 | { | ||
| 376 | memset(__bss_start, 0, _end - __bss_start); | ||
| 377 | } | ||
| 378 | |||
| 379 | /* | ||
| 380 | * Initialize storage key for kernel pages | ||
| 381 | */ | ||
| 382 | static __init void init_kernel_storage_key(void) | ||
| 383 | { | ||
| 384 | unsigned long end_pfn, init_pfn; | ||
| 385 | |||
| 386 | end_pfn = PFN_UP(__pa(&_end)); | ||
| 387 | |||
| 388 | for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++) | ||
| 389 | page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); | ||
| 390 | } | ||
| 391 | |||
| 392 | static __init void detect_machine_type(void) | ||
| 393 | { | ||
| 394 | struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; | ||
| 395 | |||
| 396 | asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id)); | ||
| 397 | |||
| 398 | /* Running under z/VM ? */ | ||
| 399 | if (cpuinfo->cpu_id.version == 0xff) | ||
| 400 | machine_flags |= 1; | ||
| 401 | |||
| 402 | /* Running on a P/390 ? */ | ||
| 403 | if (cpuinfo->cpu_id.machine == 0x7490) | ||
| 404 | machine_flags |= 4; | ||
| 405 | } | ||
| 406 | |||
| 407 | /* | ||
| 408 | * Save ipl parameters, clear bss memory, initialize storage keys | ||
| 409 | * and create a kernel NSS at startup if the SAVESYS= parm is defined | ||
| 410 | */ | ||
| 411 | void __init startup_init(void) | ||
| 412 | { | ||
| 413 | ipl_save_parameters(); | ||
| 414 | clear_bss_section(); | ||
| 415 | init_kernel_storage_key(); | ||
| 416 | lockdep_init(); | ||
| 417 | detect_machine_type(); | ||
| 418 | create_kernel_nss(); | ||
| 419 | } | ||
| 420 | |||
| 285 | #ifdef CONFIG_SMP | 421 | #ifdef CONFIG_SMP |
| 286 | void (*_machine_restart)(char *command) = machine_restart_smp; | 422 | void (*_machine_restart)(char *command) = machine_restart_smp; |
| 287 | void (*_machine_halt)(void) = machine_halt_smp; | 423 | void (*_machine_halt)(void) = machine_halt_smp; |
| @@ -523,7 +659,7 @@ setup_lowcore(void) | |||
| 523 | static void __init | 659 | static void __init |
| 524 | setup_resources(void) | 660 | setup_resources(void) |
| 525 | { | 661 | { |
| 526 | struct resource *res; | 662 | struct resource *res, *sub_res; |
| 527 | int i; | 663 | int i; |
| 528 | 664 | ||
| 529 | code_resource.start = (unsigned long) &_text; | 665 | code_resource.start = (unsigned long) &_text; |
| @@ -548,8 +684,38 @@ setup_resources(void) | |||
| 548 | res->start = memory_chunk[i].addr; | 684 | res->start = memory_chunk[i].addr; |
| 549 | res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; | 685 | res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; |
| 550 | request_resource(&iomem_resource, res); | 686 | request_resource(&iomem_resource, res); |
| 551 | request_resource(res, &code_resource); | 687 | |
| 552 | request_resource(res, &data_resource); | 688 | if (code_resource.start >= res->start && |
| 689 | code_resource.start <= res->end && | ||
| 690 | code_resource.end > res->end) { | ||
| 691 | sub_res = alloc_bootmem_low(sizeof(struct resource)); | ||
| 692 | memcpy(sub_res, &code_resource, | ||
| 693 | sizeof(struct resource)); | ||
| 694 | sub_res->end = res->end; | ||
| 695 | code_resource.start = res->end + 1; | ||
| 696 | request_resource(res, sub_res); | ||
| 697 | } | ||
| 698 | |||
| 699 | if (code_resource.start >= res->start && | ||
| 700 | code_resource.start <= res->end && | ||
| 701 | code_resource.end <= res->end) | ||
| 702 | request_resource(res, &code_resource); | ||
| 703 | |||
| 704 | if (data_resource.start >= res->start && | ||
| 705 | data_resource.start <= res->end && | ||
| 706 | data_resource.end > res->end) { | ||
| 707 | sub_res = alloc_bootmem_low(sizeof(struct resource)); | ||
| 708 | memcpy(sub_res, &data_resource, | ||
| 709 | sizeof(struct resource)); | ||
| 710 | sub_res->end = res->end; | ||
| 711 | data_resource.start = res->end + 1; | ||
| 712 | request_resource(res, sub_res); | ||
| 713 | } | ||
| 714 | |||
| 715 | if (data_resource.start >= res->start && | ||
| 716 | data_resource.start <= res->end && | ||
| 717 | data_resource.end <= res->end) | ||
| 718 | request_resource(res, &data_resource); | ||
| 553 | } | 719 | } |
| 554 | } | 720 | } |
| 555 | 721 | ||
| @@ -585,7 +751,7 @@ static void __init | |||
| 585 | setup_memory(void) | 751 | setup_memory(void) |
| 586 | { | 752 | { |
| 587 | unsigned long bootmap_size; | 753 | unsigned long bootmap_size; |
| 588 | unsigned long start_pfn, end_pfn, init_pfn; | 754 | unsigned long start_pfn, end_pfn; |
| 589 | int i; | 755 | int i; |
| 590 | 756 | ||
| 591 | /* | 757 | /* |
| @@ -595,10 +761,6 @@ setup_memory(void) | |||
| 595 | start_pfn = PFN_UP(__pa(&_end)); | 761 | start_pfn = PFN_UP(__pa(&_end)); |
| 596 | end_pfn = max_pfn = PFN_DOWN(memory_end); | 762 | end_pfn = max_pfn = PFN_DOWN(memory_end); |
| 597 | 763 | ||
| 598 | /* Initialize storage key for kernel pages */ | ||
| 599 | for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++) | ||
| 600 | page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); | ||
| 601 | |||
| 602 | #ifdef CONFIG_BLK_DEV_INITRD | 764 | #ifdef CONFIG_BLK_DEV_INITRD |
| 603 | /* | 765 | /* |
| 604 | * Move the initrd in case the bitmap of the bootmem allocater | 766 | * Move the initrd in case the bitmap of the bootmem allocater |
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index fe0f2e97ba7b..8fedb1f9fc97 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S | |||
| @@ -31,11 +31,6 @@ SECTIONS | |||
| 31 | 31 | ||
| 32 | _etext = .; /* End of text section */ | 32 | _etext = .; /* End of text section */ |
| 33 | 33 | ||
| 34 | . = ALIGN(16); /* Exception table */ | ||
| 35 | __start___ex_table = .; | ||
| 36 | __ex_table : { *(__ex_table) } | ||
| 37 | __stop___ex_table = .; | ||
| 38 | |||
| 39 | RODATA | 34 | RODATA |
| 40 | 35 | ||
| 41 | #ifdef CONFIG_SHARED_KERNEL | 36 | #ifdef CONFIG_SHARED_KERNEL |
| @@ -44,6 +39,11 @@ SECTIONS | |||
| 44 | _eshared = .; /* End of shareable data */ | 39 | _eshared = .; /* End of shareable data */ |
| 45 | #endif | 40 | #endif |
| 46 | 41 | ||
| 42 | . = ALIGN(16); /* Exception table */ | ||
| 43 | __start___ex_table = .; | ||
| 44 | __ex_table : { *(__ex_table) } | ||
| 45 | __stop___ex_table = .; | ||
| 46 | |||
| 47 | .data : { /* Data */ | 47 | .data : { /* Data */ |
| 48 | *(.data) | 48 | *(.data) |
| 49 | CONSTRUCTORS | 49 | CONSTRUCTORS |
diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h index 6b68ddda39a7..3388bb52597c 100644 --- a/include/asm-s390/setup.h +++ b/include/asm-s390/setup.h | |||
| @@ -156,13 +156,19 @@ struct ipl_parameter_block { | |||
| 156 | extern u32 ipl_flags; | 156 | extern u32 ipl_flags; |
| 157 | extern u16 ipl_devno; | 157 | extern u16 ipl_devno; |
| 158 | 158 | ||
| 159 | void do_reipl(void); | 159 | extern void do_reipl(void); |
| 160 | extern void ipl_save_parameters(void); | ||
| 160 | 161 | ||
| 161 | enum { | 162 | enum { |
| 162 | IPL_DEVNO_VALID = 1, | 163 | IPL_DEVNO_VALID = 1, |
| 163 | IPL_PARMBLOCK_VALID = 2, | 164 | IPL_PARMBLOCK_VALID = 2, |
| 165 | IPL_NSS_VALID = 4, | ||
| 164 | }; | 166 | }; |
| 165 | 167 | ||
| 168 | #define NSS_NAME_SIZE 8 | ||
| 169 | |||
| 170 | extern char kernel_nss_name[]; | ||
| 171 | |||
| 166 | #define IPL_PARMBLOCK_START ((struct ipl_parameter_block *) \ | 172 | #define IPL_PARMBLOCK_START ((struct ipl_parameter_block *) \ |
| 167 | IPL_PARMBLOCK_ORIGIN) | 173 | IPL_PARMBLOCK_ORIGIN) |
| 168 | #define IPL_PARMBLOCK_SIZE (IPL_PARMBLOCK_START->hdr.len) | 174 | #define IPL_PARMBLOCK_SIZE (IPL_PARMBLOCK_START->hdr.len) |
