aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/kexec.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/kexec.c')
-rw-r--r--kernel/kexec.c285
1 files changed, 281 insertions, 4 deletions
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 25db14b89e82..aa74a1ef2da8 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -17,21 +17,30 @@
17#include <linux/highmem.h> 17#include <linux/highmem.h>
18#include <linux/syscalls.h> 18#include <linux/syscalls.h>
19#include <linux/reboot.h> 19#include <linux/reboot.h>
20#include <linux/syscalls.h>
21#include <linux/ioport.h> 20#include <linux/ioport.h>
22#include <linux/hardirq.h> 21#include <linux/hardirq.h>
23#include <linux/elf.h> 22#include <linux/elf.h>
24#include <linux/elfcore.h> 23#include <linux/elfcore.h>
24#include <linux/utsrelease.h>
25#include <linux/utsname.h>
26#include <linux/numa.h>
25 27
26#include <asm/page.h> 28#include <asm/page.h>
27#include <asm/uaccess.h> 29#include <asm/uaccess.h>
28#include <asm/io.h> 30#include <asm/io.h>
29#include <asm/system.h> 31#include <asm/system.h>
30#include <asm/semaphore.h> 32#include <asm/semaphore.h>
33#include <asm/sections.h>
31 34
32/* Per cpu memory for storing cpu states in case of system crash. */ 35/* Per cpu memory for storing cpu states in case of system crash. */
33note_buf_t* crash_notes; 36note_buf_t* crash_notes;
34 37
38/* vmcoreinfo stuff */
39unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
40u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4];
41size_t vmcoreinfo_size;
42size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data);
43
35/* Location of the reserved area for the crash kernel */ 44/* Location of the reserved area for the crash kernel */
36struct resource crashk_res = { 45struct resource crashk_res = {
37 .name = "Crash kernel", 46 .name = "Crash kernel",
@@ -42,7 +51,7 @@ struct resource crashk_res = {
42 51
43int kexec_should_crash(struct task_struct *p) 52int kexec_should_crash(struct task_struct *p)
44{ 53{
45 if (in_interrupt() || !p->pid || is_init(p) || panic_on_oops) 54 if (in_interrupt() || !p->pid || is_global_init(p) || panic_on_oops)
46 return 1; 55 return 1;
47 return 0; 56 return 0;
48} 57}
@@ -776,7 +785,7 @@ static int kimage_load_normal_segment(struct kimage *image,
776 size_t uchunk, mchunk; 785 size_t uchunk, mchunk;
777 786
778 page = kimage_alloc_page(image, GFP_HIGHUSER, maddr); 787 page = kimage_alloc_page(image, GFP_HIGHUSER, maddr);
779 if (page == 0) { 788 if (!page) {
780 result = -ENOMEM; 789 result = -ENOMEM;
781 goto out; 790 goto out;
782 } 791 }
@@ -835,7 +844,7 @@ static int kimage_load_crash_segment(struct kimage *image,
835 size_t uchunk, mchunk; 844 size_t uchunk, mchunk;
836 845
837 page = pfn_to_page(maddr >> PAGE_SHIFT); 846 page = pfn_to_page(maddr >> PAGE_SHIFT);
838 if (page == 0) { 847 if (!page) {
839 result = -ENOMEM; 848 result = -ENOMEM;
840 goto out; 849 goto out;
841 } 850 }
@@ -1061,6 +1070,7 @@ void crash_kexec(struct pt_regs *regs)
1061 if (kexec_crash_image) { 1070 if (kexec_crash_image) {
1062 struct pt_regs fixed_regs; 1071 struct pt_regs fixed_regs;
1063 crash_setup_regs(&fixed_regs, regs); 1072 crash_setup_regs(&fixed_regs, regs);
1073 crash_save_vmcoreinfo();
1064 machine_crash_shutdown(&fixed_regs); 1074 machine_crash_shutdown(&fixed_regs);
1065 machine_kexec(kexec_crash_image); 1075 machine_kexec(kexec_crash_image);
1066 } 1076 }
@@ -1135,3 +1145,270 @@ static int __init crash_notes_memory_init(void)
1135 return 0; 1145 return 0;
1136} 1146}
1137module_init(crash_notes_memory_init) 1147module_init(crash_notes_memory_init)
1148
1149
1150/*
1151 * parsing the "crashkernel" commandline
1152 *
1153 * this code is intended to be called from architecture specific code
1154 */
1155
1156
1157/*
1158 * This function parses command lines in the format
1159 *
1160 * crashkernel=ramsize-range:size[,...][@offset]
1161 *
1162 * The function returns 0 on success and -EINVAL on failure.
1163 */
1164static int __init parse_crashkernel_mem(char *cmdline,
1165 unsigned long long system_ram,
1166 unsigned long long *crash_size,
1167 unsigned long long *crash_base)
1168{
1169 char *cur = cmdline, *tmp;
1170
1171 /* for each entry of the comma-separated list */
1172 do {
1173 unsigned long long start, end = ULLONG_MAX, size;
1174
1175 /* get the start of the range */
1176 start = memparse(cur, &tmp);
1177 if (cur == tmp) {
1178 pr_warning("crashkernel: Memory value expected\n");
1179 return -EINVAL;
1180 }
1181 cur = tmp;
1182 if (*cur != '-') {
1183 pr_warning("crashkernel: '-' expected\n");
1184 return -EINVAL;
1185 }
1186 cur++;
1187
1188 /* if no ':' is here, than we read the end */
1189 if (*cur != ':') {
1190 end = memparse(cur, &tmp);
1191 if (cur == tmp) {
1192 pr_warning("crashkernel: Memory "
1193 "value expected\n");
1194 return -EINVAL;
1195 }
1196 cur = tmp;
1197 if (end <= start) {
1198 pr_warning("crashkernel: end <= start\n");
1199 return -EINVAL;
1200 }
1201 }
1202
1203 if (*cur != ':') {
1204 pr_warning("crashkernel: ':' expected\n");
1205 return -EINVAL;
1206 }
1207 cur++;
1208
1209 size = memparse(cur, &tmp);
1210 if (cur == tmp) {
1211 pr_warning("Memory value expected\n");
1212 return -EINVAL;
1213 }
1214 cur = tmp;
1215 if (size >= system_ram) {
1216 pr_warning("crashkernel: invalid size\n");
1217 return -EINVAL;
1218 }
1219
1220 /* match ? */
1221 if (system_ram >= start && system_ram <= end) {
1222 *crash_size = size;
1223 break;
1224 }
1225 } while (*cur++ == ',');
1226
1227 if (*crash_size > 0) {
1228 while (*cur != ' ' && *cur != '@')
1229 cur++;
1230 if (*cur == '@') {
1231 cur++;
1232 *crash_base = memparse(cur, &tmp);
1233 if (cur == tmp) {
1234 pr_warning("Memory value expected "
1235 "after '@'\n");
1236 return -EINVAL;
1237 }
1238 }
1239 }
1240
1241 return 0;
1242}
1243
1244/*
1245 * That function parses "simple" (old) crashkernel command lines like
1246 *
1247 * crashkernel=size[@offset]
1248 *
1249 * It returns 0 on success and -EINVAL on failure.
1250 */
1251static int __init parse_crashkernel_simple(char *cmdline,
1252 unsigned long long *crash_size,
1253 unsigned long long *crash_base)
1254{
1255 char *cur = cmdline;
1256
1257 *crash_size = memparse(cmdline, &cur);
1258 if (cmdline == cur) {
1259 pr_warning("crashkernel: memory value expected\n");
1260 return -EINVAL;
1261 }
1262
1263 if (*cur == '@')
1264 *crash_base = memparse(cur+1, &cur);
1265
1266 return 0;
1267}
1268
1269/*
1270 * That function is the entry point for command line parsing and should be
1271 * called from the arch-specific code.
1272 */
1273int __init parse_crashkernel(char *cmdline,
1274 unsigned long long system_ram,
1275 unsigned long long *crash_size,
1276 unsigned long long *crash_base)
1277{
1278 char *p = cmdline, *ck_cmdline = NULL;
1279 char *first_colon, *first_space;
1280
1281 BUG_ON(!crash_size || !crash_base);
1282 *crash_size = 0;
1283 *crash_base = 0;
1284
1285 /* find crashkernel and use the last one if there are more */
1286 p = strstr(p, "crashkernel=");
1287 while (p) {
1288 ck_cmdline = p;
1289 p = strstr(p+1, "crashkernel=");
1290 }
1291
1292 if (!ck_cmdline)
1293 return -EINVAL;
1294
1295 ck_cmdline += 12; /* strlen("crashkernel=") */
1296
1297 /*
1298 * if the commandline contains a ':', then that's the extended
1299 * syntax -- if not, it must be the classic syntax
1300 */
1301 first_colon = strchr(ck_cmdline, ':');
1302 first_space = strchr(ck_cmdline, ' ');
1303 if (first_colon && (!first_space || first_colon < first_space))
1304 return parse_crashkernel_mem(ck_cmdline, system_ram,
1305 crash_size, crash_base);
1306 else
1307 return parse_crashkernel_simple(ck_cmdline, crash_size,
1308 crash_base);
1309
1310 return 0;
1311}
1312
1313
1314
1315void crash_save_vmcoreinfo(void)
1316{
1317 u32 *buf;
1318
1319 if (!vmcoreinfo_size)
1320 return;
1321
1322 vmcoreinfo_append_str("CRASHTIME=%ld", get_seconds());
1323
1324 buf = (u32 *)vmcoreinfo_note;
1325
1326 buf = append_elf_note(buf, VMCOREINFO_NOTE_NAME, 0, vmcoreinfo_data,
1327 vmcoreinfo_size);
1328
1329 final_note(buf);
1330}
1331
1332void vmcoreinfo_append_str(const char *fmt, ...)
1333{
1334 va_list args;
1335 char buf[0x50];
1336 int r;
1337
1338 va_start(args, fmt);
1339 r = vsnprintf(buf, sizeof(buf), fmt, args);
1340 va_end(args);
1341
1342 if (r + vmcoreinfo_size > vmcoreinfo_max_size)
1343 r = vmcoreinfo_max_size - vmcoreinfo_size;
1344
1345 memcpy(&vmcoreinfo_data[vmcoreinfo_size], buf, r);
1346
1347 vmcoreinfo_size += r;
1348}
1349
1350/*
1351 * provide an empty default implementation here -- architecture
1352 * code may override this
1353 */
1354void __attribute__ ((weak)) arch_crash_save_vmcoreinfo(void)
1355{}
1356
1357unsigned long __attribute__ ((weak)) paddr_vmcoreinfo_note(void)
1358{
1359 return __pa((unsigned long)(char *)&vmcoreinfo_note);
1360}
1361
1362static int __init crash_save_vmcoreinfo_init(void)
1363{
1364 vmcoreinfo_append_str("OSRELEASE=%s\n", init_uts_ns.name.release);
1365 vmcoreinfo_append_str("PAGESIZE=%ld\n", PAGE_SIZE);
1366
1367 VMCOREINFO_SYMBOL(init_uts_ns);
1368 VMCOREINFO_SYMBOL(node_online_map);
1369 VMCOREINFO_SYMBOL(swapper_pg_dir);
1370 VMCOREINFO_SYMBOL(_stext);
1371
1372#ifndef CONFIG_NEED_MULTIPLE_NODES
1373 VMCOREINFO_SYMBOL(mem_map);
1374 VMCOREINFO_SYMBOL(contig_page_data);
1375#endif
1376#ifdef CONFIG_SPARSEMEM
1377 VMCOREINFO_SYMBOL(mem_section);
1378 VMCOREINFO_LENGTH(mem_section, NR_SECTION_ROOTS);
1379 VMCOREINFO_SIZE(mem_section);
1380 VMCOREINFO_OFFSET(mem_section, section_mem_map);
1381#endif
1382 VMCOREINFO_SIZE(page);
1383 VMCOREINFO_SIZE(pglist_data);
1384 VMCOREINFO_SIZE(zone);
1385 VMCOREINFO_SIZE(free_area);
1386 VMCOREINFO_SIZE(list_head);
1387 VMCOREINFO_TYPEDEF_SIZE(nodemask_t);
1388 VMCOREINFO_OFFSET(page, flags);
1389 VMCOREINFO_OFFSET(page, _count);
1390 VMCOREINFO_OFFSET(page, mapping);
1391 VMCOREINFO_OFFSET(page, lru);
1392 VMCOREINFO_OFFSET(pglist_data, node_zones);
1393 VMCOREINFO_OFFSET(pglist_data, nr_zones);
1394#ifdef CONFIG_FLAT_NODE_MEM_MAP
1395 VMCOREINFO_OFFSET(pglist_data, node_mem_map);
1396#endif
1397 VMCOREINFO_OFFSET(pglist_data, node_start_pfn);
1398 VMCOREINFO_OFFSET(pglist_data, node_spanned_pages);
1399 VMCOREINFO_OFFSET(pglist_data, node_id);
1400 VMCOREINFO_OFFSET(zone, free_area);
1401 VMCOREINFO_OFFSET(zone, vm_stat);
1402 VMCOREINFO_OFFSET(zone, spanned_pages);
1403 VMCOREINFO_OFFSET(free_area, free_list);
1404 VMCOREINFO_OFFSET(list_head, next);
1405 VMCOREINFO_OFFSET(list_head, prev);
1406 VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER);
1407 VMCOREINFO_NUMBER(NR_FREE_PAGES);
1408
1409 arch_crash_save_vmcoreinfo();
1410
1411 return 0;
1412}
1413
1414module_init(crash_save_vmcoreinfo_init)