diff options
author | Michael Holzheu <holzheu@linux.vnet.ibm.com> | 2012-03-11 11:59:34 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-03-11 11:59:29 -0400 |
commit | 4857d4bbe9821c8d732cb84455e18e12b3d79add (patch) | |
tree | 54583e3ef5c84c04f92b7b15ea6aad8224781d9b /arch/s390/kernel | |
parent | ad252ffa2a0fbb1f37e81688322034b3af037cee (diff) |
[S390] kernel: Add OS info memory interface
In order to allow kdump based stand-alone dump, some information
has to be passed from the old kernel to the new dump kernel. This
is done via a the struct "os_info" that contains the following fields:
* crashkernel base and size
* reipl block
* vmcoreinfo
* init function
A pointer to os_info is stored at a well known storage location
and the whole structure as well as all fields are secured with
checksums.
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel')
-rw-r--r-- | arch/s390/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kernel/crash_dump.c | 37 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 42 | ||||
-rw-r--r-- | arch/s390/kernel/os_info.c | 169 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 3 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 13 |
6 files changed, 248 insertions, 18 deletions
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index b21595090499..16b0b433f1f4 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -23,7 +23,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w | |||
23 | obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \ | 23 | obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o \ |
24 | processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \ | 24 | processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o \ |
25 | debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \ | 25 | debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o \ |
26 | sysinfo.o jump_label.o lgr.o | 26 | sysinfo.o jump_label.o lgr.o os_info.o |
27 | 27 | ||
28 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) | 28 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) |
29 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) | 29 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) |
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c index c383ce440d99..cc1172b26873 100644 --- a/arch/s390/kernel/crash_dump.c +++ b/arch/s390/kernel/crash_dump.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/bootmem.h> | 14 | #include <linux/bootmem.h> |
15 | #include <linux/elf.h> | 15 | #include <linux/elf.h> |
16 | #include <asm/ipl.h> | 16 | #include <asm/ipl.h> |
17 | #include <asm/os_info.h> | ||
17 | 18 | ||
18 | #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y))) | 19 | #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y))) |
19 | #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) | 20 | #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y))) |
@@ -51,7 +52,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, | |||
51 | /* | 52 | /* |
52 | * Copy memory from old kernel | 53 | * Copy memory from old kernel |
53 | */ | 54 | */ |
54 | static int copy_from_oldmem(void *dest, void *src, size_t count) | 55 | int copy_from_oldmem(void *dest, void *src, size_t count) |
55 | { | 56 | { |
56 | unsigned long copied = 0; | 57 | unsigned long copied = 0; |
57 | int rc; | 58 | int rc; |
@@ -224,28 +225,44 @@ static void *nt_prpsinfo(void *ptr) | |||
224 | } | 225 | } |
225 | 226 | ||
226 | /* | 227 | /* |
227 | * Initialize vmcoreinfo note (new kernel) | 228 | * Get vmcoreinfo using lowcore->vmcore_info (new kernel) |
228 | */ | 229 | */ |
229 | static void *nt_vmcoreinfo(void *ptr) | 230 | static void *get_vmcoreinfo_old(unsigned long *size) |
230 | { | 231 | { |
231 | char nt_name[11], *vmcoreinfo; | 232 | char nt_name[11], *vmcoreinfo; |
232 | Elf64_Nhdr note; | 233 | Elf64_Nhdr note; |
233 | void *addr; | 234 | void *addr; |
234 | 235 | ||
235 | if (copy_from_oldmem(&addr, &S390_lowcore.vmcore_info, sizeof(addr))) | 236 | if (copy_from_oldmem(&addr, &S390_lowcore.vmcore_info, sizeof(addr))) |
236 | return ptr; | 237 | return NULL; |
237 | memset(nt_name, 0, sizeof(nt_name)); | 238 | memset(nt_name, 0, sizeof(nt_name)); |
238 | if (copy_from_oldmem(¬e, addr, sizeof(note))) | 239 | if (copy_from_oldmem(¬e, addr, sizeof(note))) |
239 | return ptr; | 240 | return NULL; |
240 | if (copy_from_oldmem(nt_name, addr + sizeof(note), sizeof(nt_name) - 1)) | 241 | if (copy_from_oldmem(nt_name, addr + sizeof(note), sizeof(nt_name) - 1)) |
241 | return ptr; | 242 | return NULL; |
242 | if (strcmp(nt_name, "VMCOREINFO") != 0) | 243 | if (strcmp(nt_name, "VMCOREINFO") != 0) |
243 | return ptr; | 244 | return NULL; |
244 | vmcoreinfo = kzalloc_panic(note.n_descsz + 1); | 245 | vmcoreinfo = kzalloc_panic(note.n_descsz); |
245 | if (copy_from_oldmem(vmcoreinfo, addr + 24, note.n_descsz)) | 246 | if (copy_from_oldmem(vmcoreinfo, addr + 24, note.n_descsz)) |
247 | return NULL; | ||
248 | *size = note.n_descsz; | ||
249 | return vmcoreinfo; | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | * Initialize vmcoreinfo note (new kernel) | ||
254 | */ | ||
255 | static void *nt_vmcoreinfo(void *ptr) | ||
256 | { | ||
257 | unsigned long size; | ||
258 | void *vmcoreinfo; | ||
259 | |||
260 | vmcoreinfo = os_info_old_entry(OS_INFO_VMCOREINFO, &size); | ||
261 | if (!vmcoreinfo) | ||
262 | vmcoreinfo = get_vmcoreinfo_old(&size); | ||
263 | if (!vmcoreinfo) | ||
246 | return ptr; | 264 | return ptr; |
247 | vmcoreinfo[note.n_descsz + 1] = 0; | 265 | return nt_init(ptr, 0, vmcoreinfo, size, "VMCOREINFO"); |
248 | return nt_init(ptr, 0, vmcoreinfo, note.n_descsz, "VMCOREINFO"); | ||
249 | } | 266 | } |
250 | 267 | ||
251 | /* | 268 | /* |
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 153e21ce2336..8342e65a140d 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <asm/sclp.h> | 28 | #include <asm/sclp.h> |
29 | #include <asm/checksum.h> | 29 | #include <asm/checksum.h> |
30 | #include <asm/debug.h> | 30 | #include <asm/debug.h> |
31 | #include <asm/os_info.h> | ||
31 | #include "entry.h" | 32 | #include "entry.h" |
32 | 33 | ||
33 | #define IPL_PARM_BLOCK_VERSION 0 | 34 | #define IPL_PARM_BLOCK_VERSION 0 |
@@ -951,6 +952,13 @@ static struct attribute_group reipl_nss_attr_group = { | |||
951 | .attrs = reipl_nss_attrs, | 952 | .attrs = reipl_nss_attrs, |
952 | }; | 953 | }; |
953 | 954 | ||
955 | static void set_reipl_block_actual(struct ipl_parameter_block *reipl_block) | ||
956 | { | ||
957 | reipl_block_actual = reipl_block; | ||
958 | os_info_entry_add(OS_INFO_REIPL_BLOCK, reipl_block_actual, | ||
959 | reipl_block->hdr.len); | ||
960 | } | ||
961 | |||
954 | /* reipl type */ | 962 | /* reipl type */ |
955 | 963 | ||
956 | static int reipl_set_type(enum ipl_type type) | 964 | static int reipl_set_type(enum ipl_type type) |
@@ -966,7 +974,7 @@ static int reipl_set_type(enum ipl_type type) | |||
966 | reipl_method = REIPL_METHOD_CCW_VM; | 974 | reipl_method = REIPL_METHOD_CCW_VM; |
967 | else | 975 | else |
968 | reipl_method = REIPL_METHOD_CCW_CIO; | 976 | reipl_method = REIPL_METHOD_CCW_CIO; |
969 | reipl_block_actual = reipl_block_ccw; | 977 | set_reipl_block_actual(reipl_block_ccw); |
970 | break; | 978 | break; |
971 | case IPL_TYPE_FCP: | 979 | case IPL_TYPE_FCP: |
972 | if (diag308_set_works) | 980 | if (diag308_set_works) |
@@ -975,7 +983,7 @@ static int reipl_set_type(enum ipl_type type) | |||
975 | reipl_method = REIPL_METHOD_FCP_RO_VM; | 983 | reipl_method = REIPL_METHOD_FCP_RO_VM; |
976 | else | 984 | else |
977 | reipl_method = REIPL_METHOD_FCP_RO_DIAG; | 985 | reipl_method = REIPL_METHOD_FCP_RO_DIAG; |
978 | reipl_block_actual = reipl_block_fcp; | 986 | set_reipl_block_actual(reipl_block_fcp); |
979 | break; | 987 | break; |
980 | case IPL_TYPE_FCP_DUMP: | 988 | case IPL_TYPE_FCP_DUMP: |
981 | reipl_method = REIPL_METHOD_FCP_DUMP; | 989 | reipl_method = REIPL_METHOD_FCP_DUMP; |
@@ -985,7 +993,7 @@ static int reipl_set_type(enum ipl_type type) | |||
985 | reipl_method = REIPL_METHOD_NSS_DIAG; | 993 | reipl_method = REIPL_METHOD_NSS_DIAG; |
986 | else | 994 | else |
987 | reipl_method = REIPL_METHOD_NSS; | 995 | reipl_method = REIPL_METHOD_NSS; |
988 | reipl_block_actual = reipl_block_nss; | 996 | set_reipl_block_actual(reipl_block_nss); |
989 | break; | 997 | break; |
990 | case IPL_TYPE_UNKNOWN: | 998 | case IPL_TYPE_UNKNOWN: |
991 | reipl_method = REIPL_METHOD_DEFAULT; | 999 | reipl_method = REIPL_METHOD_DEFAULT; |
@@ -1257,6 +1265,29 @@ static int __init reipl_fcp_init(void) | |||
1257 | return 0; | 1265 | return 0; |
1258 | } | 1266 | } |
1259 | 1267 | ||
1268 | static int __init reipl_type_init(void) | ||
1269 | { | ||
1270 | enum ipl_type reipl_type = ipl_info.type; | ||
1271 | struct ipl_parameter_block *reipl_block; | ||
1272 | unsigned long size; | ||
1273 | |||
1274 | reipl_block = os_info_old_entry(OS_INFO_REIPL_BLOCK, &size); | ||
1275 | if (!reipl_block) | ||
1276 | goto out; | ||
1277 | /* | ||
1278 | * If we have an OS info reipl block, this will be used | ||
1279 | */ | ||
1280 | if (reipl_block->hdr.pbt == DIAG308_IPL_TYPE_FCP) { | ||
1281 | memcpy(reipl_block_fcp, reipl_block, size); | ||
1282 | reipl_type = IPL_TYPE_FCP; | ||
1283 | } else if (reipl_block->hdr.pbt == DIAG308_IPL_TYPE_CCW) { | ||
1284 | memcpy(reipl_block_ccw, reipl_block, size); | ||
1285 | reipl_type = IPL_TYPE_CCW; | ||
1286 | } | ||
1287 | out: | ||
1288 | return reipl_set_type(reipl_type); | ||
1289 | } | ||
1290 | |||
1260 | static int __init reipl_init(void) | 1291 | static int __init reipl_init(void) |
1261 | { | 1292 | { |
1262 | int rc; | 1293 | int rc; |
@@ -1278,10 +1309,7 @@ static int __init reipl_init(void) | |||
1278 | rc = reipl_nss_init(); | 1309 | rc = reipl_nss_init(); |
1279 | if (rc) | 1310 | if (rc) |
1280 | return rc; | 1311 | return rc; |
1281 | rc = reipl_set_type(ipl_info.type); | 1312 | return reipl_type_init(); |
1282 | if (rc) | ||
1283 | return rc; | ||
1284 | return 0; | ||
1285 | } | 1313 | } |
1286 | 1314 | ||
1287 | static struct shutdown_action __refdata reipl_action = { | 1315 | static struct shutdown_action __refdata reipl_action = { |
diff --git a/arch/s390/kernel/os_info.c b/arch/s390/kernel/os_info.c new file mode 100644 index 000000000000..bbe522672e06 --- /dev/null +++ b/arch/s390/kernel/os_info.c | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * OS info memory interface | ||
3 | * | ||
4 | * Copyright IBM Corp. 2012 | ||
5 | * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #define KMSG_COMPONENT "os_info" | ||
9 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
10 | |||
11 | #include <linux/crash_dump.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <asm/checksum.h> | ||
14 | #include <asm/lowcore.h> | ||
15 | #include <asm/system.h> | ||
16 | #include <asm/os_info.h> | ||
17 | |||
18 | /* | ||
19 | * OS info structure has to be page aligned | ||
20 | */ | ||
21 | static struct os_info os_info __page_aligned_data; | ||
22 | |||
23 | /* | ||
24 | * Compute checksum over OS info structure | ||
25 | */ | ||
26 | u32 os_info_csum(struct os_info *os_info) | ||
27 | { | ||
28 | int size = sizeof(*os_info) - offsetof(struct os_info, version_major); | ||
29 | return csum_partial(&os_info->version_major, size, 0); | ||
30 | } | ||
31 | |||
32 | /* | ||
33 | * Add crashkernel info to OS info and update checksum | ||
34 | */ | ||
35 | void os_info_crashkernel_add(unsigned long base, unsigned long size) | ||
36 | { | ||
37 | os_info.crashkernel_addr = (u64)(unsigned long)base; | ||
38 | os_info.crashkernel_size = (u64)(unsigned long)size; | ||
39 | os_info.csum = os_info_csum(&os_info); | ||
40 | } | ||
41 | |||
42 | /* | ||
43 | * Add OS info entry and update checksum | ||
44 | */ | ||
45 | void os_info_entry_add(int nr, void *ptr, u64 size) | ||
46 | { | ||
47 | os_info.entry[nr].addr = (u64)(unsigned long)ptr; | ||
48 | os_info.entry[nr].size = size; | ||
49 | os_info.entry[nr].csum = csum_partial(ptr, size, 0); | ||
50 | os_info.csum = os_info_csum(&os_info); | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * Initialize OS info struture and set lowcore pointer | ||
55 | */ | ||
56 | void __init os_info_init(void) | ||
57 | { | ||
58 | void *ptr = &os_info; | ||
59 | |||
60 | os_info.version_major = OS_INFO_VERSION_MAJOR; | ||
61 | os_info.version_minor = OS_INFO_VERSION_MINOR; | ||
62 | os_info.magic = OS_INFO_MAGIC; | ||
63 | os_info.csum = os_info_csum(&os_info); | ||
64 | copy_to_absolute_zero(&S390_lowcore.os_info, &ptr, sizeof(ptr)); | ||
65 | } | ||
66 | |||
67 | #ifdef CONFIG_CRASH_DUMP | ||
68 | |||
69 | static struct os_info *os_info_old; | ||
70 | |||
71 | /* | ||
72 | * Allocate and copy OS info entry from oldmem | ||
73 | */ | ||
74 | static void os_info_old_alloc(int nr, int align) | ||
75 | { | ||
76 | unsigned long addr, size = 0; | ||
77 | char *buf, *buf_align, *msg; | ||
78 | u32 csum; | ||
79 | |||
80 | addr = os_info_old->entry[nr].addr; | ||
81 | if (!addr) { | ||
82 | msg = "not available"; | ||
83 | goto fail; | ||
84 | } | ||
85 | size = os_info_old->entry[nr].size; | ||
86 | buf = kmalloc(size + align - 1, GFP_KERNEL); | ||
87 | if (!buf) { | ||
88 | msg = "alloc failed"; | ||
89 | goto fail; | ||
90 | } | ||
91 | buf_align = PTR_ALIGN(buf, align); | ||
92 | if (copy_from_oldmem(buf_align, (void *) addr, size)) { | ||
93 | msg = "copy failed"; | ||
94 | goto fail_free; | ||
95 | } | ||
96 | csum = csum_partial(buf_align, size, 0); | ||
97 | if (csum != os_info_old->entry[nr].csum) { | ||
98 | msg = "checksum failed"; | ||
99 | goto fail_free; | ||
100 | } | ||
101 | os_info_old->entry[nr].addr = (u64)(unsigned long)buf_align; | ||
102 | msg = "copied"; | ||
103 | goto out; | ||
104 | fail_free: | ||
105 | kfree(buf); | ||
106 | fail: | ||
107 | os_info_old->entry[nr].addr = 0; | ||
108 | out: | ||
109 | pr_info("entry %i: %s (addr=0x%lx size=%lu)\n", | ||
110 | nr, msg, addr, size); | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * Initialize os info and os info entries from oldmem | ||
115 | */ | ||
116 | static void os_info_old_init(void) | ||
117 | { | ||
118 | static int os_info_init; | ||
119 | unsigned long addr; | ||
120 | |||
121 | if (os_info_init) | ||
122 | return; | ||
123 | if (!OLDMEM_BASE) | ||
124 | goto fail; | ||
125 | if (copy_from_oldmem(&addr, &S390_lowcore.os_info, sizeof(addr))) | ||
126 | goto fail; | ||
127 | if (addr == 0 || addr % PAGE_SIZE) | ||
128 | goto fail; | ||
129 | os_info_old = kzalloc(sizeof(*os_info_old), GFP_KERNEL); | ||
130 | if (!os_info_old) | ||
131 | goto fail; | ||
132 | if (copy_from_oldmem(os_info_old, (void *) addr, sizeof(*os_info_old))) | ||
133 | goto fail_free; | ||
134 | if (os_info_old->magic != OS_INFO_MAGIC) | ||
135 | goto fail_free; | ||
136 | if (os_info_old->csum != os_info_csum(os_info_old)) | ||
137 | goto fail_free; | ||
138 | if (os_info_old->version_major > OS_INFO_VERSION_MAJOR) | ||
139 | goto fail_free; | ||
140 | os_info_old_alloc(OS_INFO_VMCOREINFO, 1); | ||
141 | os_info_old_alloc(OS_INFO_REIPL_BLOCK, 1); | ||
142 | os_info_old_alloc(OS_INFO_INIT_FN, PAGE_SIZE); | ||
143 | pr_info("crashkernel: addr=0x%lx size=%lu\n", | ||
144 | (unsigned long) os_info_old->crashkernel_addr, | ||
145 | (unsigned long) os_info_old->crashkernel_size); | ||
146 | os_info_init = 1; | ||
147 | return; | ||
148 | fail_free: | ||
149 | kfree(os_info_old); | ||
150 | fail: | ||
151 | os_info_init = 1; | ||
152 | os_info_old = NULL; | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * Return pointer to os infor entry and its size | ||
157 | */ | ||
158 | void *os_info_old_entry(int nr, unsigned long *size) | ||
159 | { | ||
160 | os_info_old_init(); | ||
161 | |||
162 | if (!os_info_old) | ||
163 | return NULL; | ||
164 | if (!os_info_old->entry[nr].addr) | ||
165 | return NULL; | ||
166 | *size = (unsigned long) os_info_old->entry[nr].size; | ||
167 | return (void *)(unsigned long)os_info_old->entry[nr].addr; | ||
168 | } | ||
169 | #endif | ||
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 9a3edb5f2c92..38e751278bf7 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <asm/ebcdic.h> | 62 | #include <asm/ebcdic.h> |
63 | #include <asm/kvm_virtio.h> | 63 | #include <asm/kvm_virtio.h> |
64 | #include <asm/diag.h> | 64 | #include <asm/diag.h> |
65 | #include <asm/os_info.h> | ||
65 | #include "entry.h" | 66 | #include "entry.h" |
66 | 67 | ||
67 | long psw_kernel_bits = PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_ASC_PRIMARY | | 68 | long psw_kernel_bits = PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_ASC_PRIMARY | |
@@ -778,6 +779,7 @@ static void __init reserve_crashkernel(void) | |||
778 | pr_info("Reserving %lluMB of memory at %lluMB " | 779 | pr_info("Reserving %lluMB of memory at %lluMB " |
779 | "for crashkernel (System RAM: %luMB)\n", | 780 | "for crashkernel (System RAM: %luMB)\n", |
780 | crash_size >> 20, crash_base >> 20, memory_end >> 20); | 781 | crash_size >> 20, crash_base >> 20, memory_end >> 20); |
782 | os_info_crashkernel_add(crash_base, crash_size); | ||
781 | #endif | 783 | #endif |
782 | } | 784 | } |
783 | 785 | ||
@@ -1057,6 +1059,7 @@ void __init setup_arch(char **cmdline_p) | |||
1057 | 1059 | ||
1058 | parse_early_param(); | 1060 | parse_early_param(); |
1059 | 1061 | ||
1062 | os_info_init(); | ||
1060 | setup_ipl(); | 1063 | setup_ipl(); |
1061 | setup_memory_end(); | 1064 | setup_memory_end(); |
1062 | setup_addressing_mode(); | 1065 | setup_addressing_mode(); |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index d15b6c937088..3b9e5c9f4c0b 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <asm/sclp.h> | 41 | #include <asm/sclp.h> |
42 | #include <asm/vdso.h> | 42 | #include <asm/vdso.h> |
43 | #include <asm/debug.h> | 43 | #include <asm/debug.h> |
44 | #include <asm/os_info.h> | ||
44 | #include "entry.h" | 45 | #include "entry.h" |
45 | 46 | ||
46 | enum { | 47 | enum { |
@@ -826,6 +827,17 @@ void __noreturn cpu_die(void) | |||
826 | 827 | ||
827 | #endif /* CONFIG_HOTPLUG_CPU */ | 828 | #endif /* CONFIG_HOTPLUG_CPU */ |
828 | 829 | ||
830 | static void smp_call_os_info_init_fn(void) | ||
831 | { | ||
832 | int (*init_fn)(void); | ||
833 | unsigned long size; | ||
834 | |||
835 | init_fn = os_info_old_entry(OS_INFO_INIT_FN, &size); | ||
836 | if (!init_fn) | ||
837 | return; | ||
838 | init_fn(); | ||
839 | } | ||
840 | |||
829 | void __init smp_prepare_cpus(unsigned int max_cpus) | 841 | void __init smp_prepare_cpus(unsigned int max_cpus) |
830 | { | 842 | { |
831 | /* request the 0x1201 emergency signal external interrupt */ | 843 | /* request the 0x1201 emergency signal external interrupt */ |
@@ -834,6 +846,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
834 | /* request the 0x1202 external call external interrupt */ | 846 | /* request the 0x1202 external call external interrupt */ |
835 | if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0) | 847 | if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0) |
836 | panic("Couldn't request external interrupt 0x1202"); | 848 | panic("Couldn't request external interrupt 0x1202"); |
849 | smp_call_os_info_init_fn(); | ||
837 | smp_detect_cpus(); | 850 | smp_detect_cpus(); |
838 | } | 851 | } |
839 | 852 | ||