/* * 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.
*/ staticint __init parse_crashkernel_mem(char *cmdline, unsignedlonglong system_ram, unsignedlonglong *crash_size, unsignedlonglong *crash_base)
{ char *cur = cmdline, *tmp; unsignedlonglong total_mem = system_ram;
/* * Firmware sometimes reserves some memory regions for its own use, * so the system memory size is less than the actual physical memory * size. Work around this by rounding up the total size to 128M, * which is enough for most test cases.
*/
total_mem = roundup(total_mem, SZ_128M);
/* for each entry of the comma-separated list */ do { unsignedlonglong start, end = ULLONG_MAX, size;
/* get the start of the range */
start = memparse(cur, &tmp); if (cur == tmp) {
pr_warn("crashkernel: Memory value expected\n"); return -EINVAL;
}
cur = tmp; if (*cur != '-') {
pr_warn("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_warn("crashkernel: Memory value expected\n"); return -EINVAL;
}
cur = tmp; if (end <= start) {
pr_warn("crashkernel: end <= start\n"); return -EINVAL;
}
}
ck_cmdline = get_last_crashkernel(cmdline, name, suffix); if (!ck_cmdline) return -ENOENT;
ck_cmdline += strlen(name);
if (suffix) return parse_crashkernel_suffix(ck_cmdline, crash_size,
suffix); /* * 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);
/* * That function is the entry point for command line parsing and should be * called from the arch-specific code. * * If crashkernel=,high|low is supported on architecture, non-NULL values * should be passed to parameters 'low_size' and 'high'.
*/ int __init parse_crashkernel(char *cmdline, unsignedlonglong system_ram, unsignedlonglong *crash_size, unsignedlonglong *crash_base, unsignedlonglong *low_size, unsignedlonglong *cma_size, bool *high)
{ int ret; unsignedlonglong __always_unused cma_base;
/* crashkernel=X[@offset] */
ret = __parse_crashkernel(cmdline, system_ram, crash_size,
crash_base, NULL); #ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION /* * If non-NULL 'high' passed in and no normal crashkernel * setting detected, try parsing crashkernel=,high|low.
*/ if (high && ret == -ENOENT) {
ret = __parse_crashkernel(cmdline, 0, crash_size,
crash_base, suffix_tbl[SUFFIX_HIGH]); if (ret || !*crash_size) return -EINVAL;
/* * crashkernel=Y,low can be specified or not, but invalid value * is not allowed.
*/
ret = __parse_crashkernel(cmdline, 0, low_size,
crash_base, suffix_tbl[SUFFIX_LOW]); if (ret == -ENOENT) {
*low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
ret = 0;
} elseif (ret) { return ret;
}
*high = true;
}
/* * optional CMA reservation * cma_base is ignored
*/ if (cma_size)
__parse_crashkernel(cmdline, 0, cma_size,
&cma_base, suffix_tbl[SUFFIX_CMA]); #endif if (!*crash_size)
ret = -EINVAL;
if (*crash_size >= system_ram)
ret = -EINVAL;
return ret;
}
/* * Add a dummy early_param handler to mark crashkernel= as a known command line * parameter and suppress incorrect warnings in init/main.c.
*/ staticint __init parse_crashkernel_dummy(char *arg)
{ return 0;
}
early_param("crashkernel", parse_crashkernel_dummy);
retry:
crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
search_base, search_end); if (!crash_base) { /* * For crashkernel=size[KMG]@offset[KMG], print out failure * message if can't reserve the specified region.
*/ if (fixed_base) {
pr_warn("crashkernel reservation failed - memory is in use.\n"); return;
}
/* * For crashkernel=size[KMG], if the first attempt was for * low memory, fall back to high memory, the minimum required * low memory will be reserved later.
*/ if (!high && search_end == CRASH_ADDR_LOW_MAX) {
search_end = CRASH_ADDR_HIGH_MAX;
search_base = CRASH_ADDR_LOW_MAX;
crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE; goto retry;
}
/* * For crashkernel=size[KMG],high, if the first attempt was * for high memory, fall back to low memory.
*/ if (high && search_end == CRASH_ADDR_HIGH_MAX) {
search_end = CRASH_ADDR_LOW_MAX;
search_base = 0; if (search_end != CRASH_ADDR_HIGH_MAX) goto retry;
}
pr_warn("cannot allocate crashkernel (size:0x%llx)\n",
crash_size); return;
}
/* * The crashkernel memory will be removed from the kernel linear * map. Inform kmemleak so that it won't try to access it.
*/
kmemleak_ignore_phys(crash_base); if (crashk_low_res.end)
kmemleak_ignore_phys(crashk_low_res.start);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.