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