Merge remote branch 'linus/master'
[powerpc.git] / kernel / kexec.c
index 67828be..06a0e27 100644 (file)
@@ -38,8 +38,8 @@ note_buf_t* crash_notes;
 /* vmcoreinfo stuff */
 unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
 u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4];
-unsigned int vmcoreinfo_size = 0;
-unsigned int vmcoreinfo_max_size = sizeof(vmcoreinfo_data);
+size_t vmcoreinfo_size;
+size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data);
 
 /* Location of the reserved area for the crash kernel */
 struct resource crashk_res = {
@@ -51,7 +51,7 @@ struct resource crashk_res = {
 
 int kexec_should_crash(struct task_struct *p)
 {
-       if (in_interrupt() || !p->pid || is_init(p) || panic_on_oops)
+       if (in_interrupt() || !p->pid || is_global_init(p) || panic_on_oops)
                return 1;
        return 0;
 }
@@ -785,7 +785,7 @@ static int kimage_load_normal_segment(struct kimage *image,
                size_t uchunk, mchunk;
 
                page = kimage_alloc_page(image, GFP_HIGHUSER, maddr);
-               if (page == 0) {
+               if (!page) {
                        result  = -ENOMEM;
                        goto out;
                }
@@ -844,7 +844,7 @@ static int kimage_load_crash_segment(struct kimage *image,
                size_t uchunk, mchunk;
 
                page = pfn_to_page(maddr >> PAGE_SHIFT);
-               if (page == 0) {
+               if (!page) {
                        result  = -ENOMEM;
                        goto out;
                }
@@ -1146,6 +1146,172 @@ static int __init crash_notes_memory_init(void)
 }
 module_init(crash_notes_memory_init)
 
+
+/*
+ * parsing the "crashkernel" commandline
+ *
+ * this code is intended to be called from architecture specific code
+ */
+
+
+/*
+ * This function parses command lines in the format
+ *
+ *   crashkernel=ramsize-range:size[,...][@offset]
+ *
+ * The function returns 0 on success and -EINVAL on failure.
+ */
+static int __init parse_crashkernel_mem(char                   *cmdline,
+                                       unsigned long long      system_ram,
+                                       unsigned long long      *crash_size,
+                                       unsigned long long      *crash_base)
+{
+       char *cur = cmdline, *tmp;
+
+       /* for each entry of the comma-separated list */
+       do {
+               unsigned long long start, end = ULLONG_MAX, size;
+
+               /* get the start of the range */
+               start = memparse(cur, &tmp);
+               if (cur == tmp) {
+                       pr_warning("crashkernel: Memory value expected\n");
+                       return -EINVAL;
+               }
+               cur = tmp;
+               if (*cur != '-') {
+                       pr_warning("crashkernel: '-' expected\n");
+                       return -EINVAL;
+               }
+               cur++;
+
+               /* if no ':' is here, than we read the end */
+               if (*cur != ':') {
+                       end = memparse(cur, &tmp);
+                       if (cur == tmp) {
+                               pr_warning("crashkernel: Memory "
+                                               "value expected\n");
+                               return -EINVAL;
+                       }
+                       cur = tmp;
+                       if (end <= start) {
+                               pr_warning("crashkernel: end <= start\n");
+                               return -EINVAL;
+                       }
+               }
+
+               if (*cur != ':') {
+                       pr_warning("crashkernel: ':' expected\n");
+                       return -EINVAL;
+               }
+               cur++;
+
+               size = memparse(cur, &tmp);
+               if (cur == tmp) {
+                       pr_warning("Memory value expected\n");
+                       return -EINVAL;
+               }
+               cur = tmp;
+               if (size >= system_ram) {
+                       pr_warning("crashkernel: invalid size\n");
+                       return -EINVAL;
+               }
+
+               /* match ? */
+               if (system_ram >= start && system_ram <= end) {
+                       *crash_size = size;
+                       break;
+               }
+       } while (*cur++ == ',');
+
+       if (*crash_size > 0) {
+               while (*cur != ' ' && *cur != '@')
+                       cur++;
+               if (*cur == '@') {
+                       cur++;
+                       *crash_base = memparse(cur, &tmp);
+                       if (cur == tmp) {
+                               pr_warning("Memory value expected "
+                                               "after '@'\n");
+                               return -EINVAL;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * That function parses "simple" (old) crashkernel command lines like
+ *
+ *     crashkernel=size[@offset]
+ *
+ * It returns 0 on success and -EINVAL on failure.
+ */
+static int __init parse_crashkernel_simple(char                *cmdline,
+                                          unsigned long long   *crash_size,
+                                          unsigned long long   *crash_base)
+{
+       char *cur = cmdline;
+
+       *crash_size = memparse(cmdline, &cur);
+       if (cmdline == cur) {
+               pr_warning("crashkernel: memory value expected\n");
+               return -EINVAL;
+       }
+
+       if (*cur == '@')
+               *crash_base = memparse(cur+1, &cur);
+
+       return 0;
+}
+
+/*
+ * That function is the entry point for command line parsing and should be
+ * called from the arch-specific code.
+ */
+int __init parse_crashkernel(char               *cmdline,
+                            unsigned long long system_ram,
+                            unsigned long long *crash_size,
+                            unsigned long long *crash_base)
+{
+       char    *p = cmdline, *ck_cmdline = NULL;
+       char    *first_colon, *first_space;
+
+       BUG_ON(!crash_size || !crash_base);
+       *crash_size = 0;
+       *crash_base = 0;
+
+       /* find crashkernel and use the last one if there are more */
+       p = strstr(p, "crashkernel=");
+       while (p) {
+               ck_cmdline = p;
+               p = strstr(p+1, "crashkernel=");
+       }
+
+       if (!ck_cmdline)
+               return -EINVAL;
+
+       ck_cmdline += 12; /* strlen("crashkernel=") */
+
+       /*
+        * if the commandline contains a ':', then that's the extended
+        * syntax -- if not, it must be the classic syntax
+        */
+       first_colon = strchr(ck_cmdline, ':');
+       first_space = strchr(ck_cmdline, ' ');
+       if (first_colon && (!first_space || first_colon < first_space))
+               return parse_crashkernel_mem(ck_cmdline, system_ram,
+                               crash_size, crash_base);
+       else
+               return parse_crashkernel_simple(ck_cmdline, crash_size,
+                               crash_base);
+
+       return 0;
+}
+
+
+
 void crash_save_vmcoreinfo(void)
 {
        u32 *buf;
@@ -1153,7 +1319,7 @@ void crash_save_vmcoreinfo(void)
        if (!vmcoreinfo_size)
                return;
 
-       vmcoreinfo_append_str("CRASHTIME=%d", xtime.tv_sec);
+       vmcoreinfo_append_str("CRASHTIME=%ld", get_seconds());
 
        buf = (u32 *)vmcoreinfo_note;
 
@@ -1195,48 +1361,51 @@ unsigned long __attribute__ ((weak)) paddr_vmcoreinfo_note(void)
 
 static int __init crash_save_vmcoreinfo_init(void)
 {
-       vmcoreinfo_append_str("OSRELEASE=%s\n", UTS_RELEASE);
-       vmcoreinfo_append_str("PAGESIZE=%d\n", PAGE_SIZE);
+       VMCOREINFO_OSRELEASE(init_uts_ns.name.release);
+       VMCOREINFO_PAGESIZE(PAGE_SIZE);
 
-       SYMBOL(init_uts_ns);
-       SYMBOL(node_online_map);
-       SYMBOL(swapper_pg_dir);
-       SYMBOL(_stext);
+       VMCOREINFO_SYMBOL(init_uts_ns);
+       VMCOREINFO_SYMBOL(node_online_map);
+       VMCOREINFO_SYMBOL(swapper_pg_dir);
+       VMCOREINFO_SYMBOL(_stext);
 
 #ifndef CONFIG_NEED_MULTIPLE_NODES
-       SYMBOL(mem_map);
-       SYMBOL(contig_page_data);
+       VMCOREINFO_SYMBOL(mem_map);
+       VMCOREINFO_SYMBOL(contig_page_data);
 #endif
 #ifdef CONFIG_SPARSEMEM
-       SYMBOL(mem_section);
-       LENGTH(mem_section, NR_SECTION_ROOTS);
-       SIZE(mem_section);
-       OFFSET(mem_section, section_mem_map);
+       VMCOREINFO_SYMBOL(mem_section);
+       VMCOREINFO_LENGTH(mem_section, NR_SECTION_ROOTS);
+       VMCOREINFO_STRUCT_SIZE(mem_section);
+       VMCOREINFO_OFFSET(mem_section, section_mem_map);
 #endif
-       SIZE(page);
-       SIZE(pglist_data);
-       SIZE(zone);
-       SIZE(free_area);
-       SIZE(list_head);
-       OFFSET(page, flags);
-       OFFSET(page, _count);
-       OFFSET(page, mapping);
-       OFFSET(page, lru);
-       OFFSET(pglist_data, node_zones);
-       OFFSET(pglist_data, nr_zones);
+       VMCOREINFO_STRUCT_SIZE(page);
+       VMCOREINFO_STRUCT_SIZE(pglist_data);
+       VMCOREINFO_STRUCT_SIZE(zone);
+       VMCOREINFO_STRUCT_SIZE(free_area);
+       VMCOREINFO_STRUCT_SIZE(list_head);
+       VMCOREINFO_SIZE(nodemask_t);
+       VMCOREINFO_OFFSET(page, flags);
+       VMCOREINFO_OFFSET(page, _count);
+       VMCOREINFO_OFFSET(page, mapping);
+       VMCOREINFO_OFFSET(page, lru);
+       VMCOREINFO_OFFSET(pglist_data, node_zones);
+       VMCOREINFO_OFFSET(pglist_data, nr_zones);
 #ifdef CONFIG_FLAT_NODE_MEM_MAP
-       OFFSET(pglist_data, node_mem_map);
+       VMCOREINFO_OFFSET(pglist_data, node_mem_map);
 #endif
-       OFFSET(pglist_data, node_start_pfn);
-       OFFSET(pglist_data, node_spanned_pages);
-       OFFSET(pglist_data, node_id);
-       OFFSET(zone, free_area);
-       OFFSET(zone, vm_stat);
-       OFFSET(zone, spanned_pages);
-       OFFSET(free_area, free_list);
-       OFFSET(list_head, next);
-       OFFSET(list_head, prev);
-       LENGTH(zone.free_area, MAX_ORDER);
+       VMCOREINFO_OFFSET(pglist_data, node_start_pfn);
+       VMCOREINFO_OFFSET(pglist_data, node_spanned_pages);
+       VMCOREINFO_OFFSET(pglist_data, node_id);
+       VMCOREINFO_OFFSET(zone, free_area);
+       VMCOREINFO_OFFSET(zone, vm_stat);
+       VMCOREINFO_OFFSET(zone, spanned_pages);
+       VMCOREINFO_OFFSET(free_area, free_list);
+       VMCOREINFO_OFFSET(list_head, next);
+       VMCOREINFO_OFFSET(list_head, prev);
+       VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER);
+       VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES);
+       VMCOREINFO_NUMBER(NR_FREE_PAGES);
 
        arch_crash_save_vmcoreinfo();