combination with the `low_crashinfo` command line option.
### crashkernel
-> `= <ramsize-range>:<size>[,...][@<offset>]`
+> `= <ramsize-range>:<size>[,...][{@,<}<offset>]`
+> `= <size>[{@,<}<offset>]`
+
+Specify sizes and optionally placement of the crash kernel reservation
+area. The `<ramsize-range>:<size>` pairs indicate how much memory to
+set aside for a crash kernel (`<size>`) for a given range of installed
+RAM (`<ramsize-range>`). Each `<ramsize-range>` is of the form
+`<start>-[<end>]`.
+
+A trailing `@<offset>` specifies the exact address this area should be
+placed at, whereas `<` in place of `@` just specifies an upper bound of
+the address range the area should fall into.
### credit2\_balance\_over
> `= <integer>`
}
#ifdef CONFIG_KEXEC
- /* Don't overlap with modules. */
- e = consider_modules(s, e, PAGE_ALIGN(kexec_crash_area.size),
- mod, mbi->mods_count, -1);
- if ( !kexec_crash_area.start && (s < e) )
+ /*
+ * Looking backwards from the crash area limit, find a large
+ * enough range that does not overlap with modules.
+ */
+ while ( !kexec_crash_area.start )
{
- e = (e - kexec_crash_area.size) & PAGE_MASK;
- kexec_crash_area.start = e;
+ /* Don't overlap with modules. */
+ e = consider_modules(s, e, PAGE_ALIGN(kexec_crash_area.size),
+ mod, mbi->mods_count, -1);
+ if ( s >= e )
+ break;
+ if ( e > kexec_crash_area_limit )
+ {
+ e = kexec_crash_area_limit & PAGE_MASK;
+ continue;
+ }
+ kexec_crash_area.start = (e - kexec_crash_area.size) & PAGE_MASK;
}
#endif
}
static size_t vmcoreinfo_size = 0;
xen_kexec_reserve_t kexec_crash_area;
+paddr_t __initdata kexec_crash_area_limit = ~(paddr_t)0;
static struct {
u64 start, end;
unsigned long size;
/*
* Parse command lines in the format
*
- * crashkernel=<ramsize-range>:<size>[,...][@<offset>]
+ * crashkernel=<ramsize-range>:<size>[,...][{@,<}<address>]
*
* with <ramsize-range> being of form
*
*
* as well as the legacy ones in the format
*
- * crashkernel=<size>[@<offset>]
+ * crashkernel=<size>[{@,<}<address>]
*/
static void __init parse_crashkernel(const char *str)
{
{
printk(XENLOG_WARNING "crashkernel: too many ranges\n");
cur = NULL;
- str = strchr(str, '@');
+ str = strpbrk(str, "@<");
break;
}
}
else
kexec_crash_area.size = parse_size_and_unit(cur = str, &str);
- if ( cur != str && *str == '@' )
- kexec_crash_area.start = parse_size_and_unit(cur = str + 1, &str);
- if ( cur == str )
+ if ( cur != str )
+ {
+ if ( *str == '@' )
+ kexec_crash_area.start = parse_size_and_unit(cur = str + 1, &str);
+ else if ( *str == '<' )
+ kexec_crash_area_limit = parse_size_and_unit(cur = str + 1, &str);
+ else
+ printk(XENLOG_WARNING "crashkernel: '%s' ignored\n", str);
+ }
+ if ( cur && cur == str )
printk(XENLOG_WARNING "crashkernel: memory value expected\n");
}
custom_param("crashkernel", parse_crashkernel);
} xen_kexec_reserve_t;
extern xen_kexec_reserve_t kexec_crash_area;
+extern paddr_t kexec_crash_area_limit;
extern bool_t kexecing;