|
@@ -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;
|