crash_reserve.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * crash.c - kernel crash support code.
  4. * Copyright (C) 2002-2004 Eric Biederman <ebiederm@xmission.com>
  5. */
  6. #include <linux/buildid.h>
  7. #include <linux/init.h>
  8. #include <linux/utsname.h>
  9. #include <linux/vmalloc.h>
  10. #include <linux/sizes.h>
  11. #include <linux/kexec.h>
  12. #include <linux/memory.h>
  13. #include <linux/cpuhotplug.h>
  14. #include <linux/memblock.h>
  15. #include <linux/kmemleak.h>
  16. #include <asm/page.h>
  17. #include <asm/sections.h>
  18. #include <crypto/sha1.h>
  19. #include "kallsyms_internal.h"
  20. #include "kexec_internal.h"
  21. /* Location of the reserved area for the crash kernel */
  22. struct resource crashk_res = {
  23. .name = "Crash kernel",
  24. .start = 0,
  25. .end = 0,
  26. .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM,
  27. .desc = IORES_DESC_CRASH_KERNEL
  28. };
  29. struct resource crashk_low_res = {
  30. .name = "Crash kernel",
  31. .start = 0,
  32. .end = 0,
  33. .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM,
  34. .desc = IORES_DESC_CRASH_KERNEL
  35. };
  36. /*
  37. * parsing the "crashkernel" commandline
  38. *
  39. * this code is intended to be called from architecture specific code
  40. */
  41. /*
  42. * This function parses command lines in the format
  43. *
  44. * crashkernel=ramsize-range:size[,...][@offset]
  45. *
  46. * The function returns 0 on success and -EINVAL on failure.
  47. */
  48. static int __init parse_crashkernel_mem(char *cmdline,
  49. unsigned long long system_ram,
  50. unsigned long long *crash_size,
  51. unsigned long long *crash_base)
  52. {
  53. char *cur = cmdline, *tmp;
  54. unsigned long long total_mem = system_ram;
  55. /*
  56. * Firmware sometimes reserves some memory regions for its own use,
  57. * so the system memory size is less than the actual physical memory
  58. * size. Work around this by rounding up the total size to 128M,
  59. * which is enough for most test cases.
  60. */
  61. total_mem = roundup(total_mem, SZ_128M);
  62. /* for each entry of the comma-separated list */
  63. do {
  64. unsigned long long start, end = ULLONG_MAX, size;
  65. /* get the start of the range */
  66. start = memparse(cur, &tmp);
  67. if (cur == tmp) {
  68. pr_warn("crashkernel: Memory value expected\n");
  69. return -EINVAL;
  70. }
  71. cur = tmp;
  72. if (*cur != '-') {
  73. pr_warn("crashkernel: '-' expected\n");
  74. return -EINVAL;
  75. }
  76. cur++;
  77. /* if no ':' is here, than we read the end */
  78. if (*cur != ':') {
  79. end = memparse(cur, &tmp);
  80. if (cur == tmp) {
  81. pr_warn("crashkernel: Memory value expected\n");
  82. return -EINVAL;
  83. }
  84. cur = tmp;
  85. if (end <= start) {
  86. pr_warn("crashkernel: end <= start\n");
  87. return -EINVAL;
  88. }
  89. }
  90. if (*cur != ':') {
  91. pr_warn("crashkernel: ':' expected\n");
  92. return -EINVAL;
  93. }
  94. cur++;
  95. size = memparse(cur, &tmp);
  96. if (cur == tmp) {
  97. pr_warn("crashkernel: Memory value expected\n");
  98. return -EINVAL;
  99. }
  100. cur = tmp;
  101. if (size >= total_mem) {
  102. pr_warn("crashkernel: invalid size\n");
  103. return -EINVAL;
  104. }
  105. /* match ? */
  106. if (total_mem >= start && total_mem < end) {
  107. *crash_size = size;
  108. break;
  109. }
  110. } while (*cur++ == ',');
  111. if (*crash_size > 0) {
  112. while (*cur && *cur != ' ' && *cur != '@')
  113. cur++;
  114. if (*cur == '@') {
  115. cur++;
  116. *crash_base = memparse(cur, &tmp);
  117. if (cur == tmp) {
  118. pr_warn("crahskernel: Memory value expected after '@'\n");
  119. return -EINVAL;
  120. }
  121. }
  122. } else
  123. pr_info("crashkernel size resulted in zero bytes\n");
  124. return 0;
  125. }
  126. /*
  127. * That function parses "simple" (old) crashkernel command lines like
  128. *
  129. * crashkernel=size[@offset]
  130. *
  131. * It returns 0 on success and -EINVAL on failure.
  132. */
  133. static int __init parse_crashkernel_simple(char *cmdline,
  134. unsigned long long *crash_size,
  135. unsigned long long *crash_base)
  136. {
  137. char *cur = cmdline;
  138. *crash_size = memparse(cmdline, &cur);
  139. if (cmdline == cur) {
  140. pr_warn("crashkernel: memory value expected\n");
  141. return -EINVAL;
  142. }
  143. if (*cur == '@')
  144. *crash_base = memparse(cur+1, &cur);
  145. else if (*cur != ' ' && *cur != '\0') {
  146. pr_warn("crashkernel: unrecognized char: %c\n", *cur);
  147. return -EINVAL;
  148. }
  149. return 0;
  150. }
  151. #define SUFFIX_HIGH 0
  152. #define SUFFIX_LOW 1
  153. #define SUFFIX_NULL 2
  154. static __initdata char *suffix_tbl[] = {
  155. [SUFFIX_HIGH] = ",high",
  156. [SUFFIX_LOW] = ",low",
  157. [SUFFIX_NULL] = NULL,
  158. };
  159. /*
  160. * That function parses "suffix" crashkernel command lines like
  161. *
  162. * crashkernel=size,[high|low]
  163. *
  164. * It returns 0 on success and -EINVAL on failure.
  165. */
  166. static int __init parse_crashkernel_suffix(char *cmdline,
  167. unsigned long long *crash_size,
  168. const char *suffix)
  169. {
  170. char *cur = cmdline;
  171. *crash_size = memparse(cmdline, &cur);
  172. if (cmdline == cur) {
  173. pr_warn("crashkernel: memory value expected\n");
  174. return -EINVAL;
  175. }
  176. /* check with suffix */
  177. if (strncmp(cur, suffix, strlen(suffix))) {
  178. pr_warn("crashkernel: unrecognized char: %c\n", *cur);
  179. return -EINVAL;
  180. }
  181. cur += strlen(suffix);
  182. if (*cur != ' ' && *cur != '\0') {
  183. pr_warn("crashkernel: unrecognized char: %c\n", *cur);
  184. return -EINVAL;
  185. }
  186. return 0;
  187. }
  188. static __init char *get_last_crashkernel(char *cmdline,
  189. const char *name,
  190. const char *suffix)
  191. {
  192. char *p = cmdline, *ck_cmdline = NULL;
  193. /* find crashkernel and use the last one if there are more */
  194. p = strstr(p, name);
  195. while (p) {
  196. char *end_p = strchr(p, ' ');
  197. char *q;
  198. if (!end_p)
  199. end_p = p + strlen(p);
  200. if (!suffix) {
  201. int i;
  202. /* skip the one with any known suffix */
  203. for (i = 0; suffix_tbl[i]; i++) {
  204. q = end_p - strlen(suffix_tbl[i]);
  205. if (!strncmp(q, suffix_tbl[i],
  206. strlen(suffix_tbl[i])))
  207. goto next;
  208. }
  209. ck_cmdline = p;
  210. } else {
  211. q = end_p - strlen(suffix);
  212. if (!strncmp(q, suffix, strlen(suffix)))
  213. ck_cmdline = p;
  214. }
  215. next:
  216. p = strstr(p+1, name);
  217. }
  218. return ck_cmdline;
  219. }
  220. static int __init __parse_crashkernel(char *cmdline,
  221. unsigned long long system_ram,
  222. unsigned long long *crash_size,
  223. unsigned long long *crash_base,
  224. const char *suffix)
  225. {
  226. char *first_colon, *first_space;
  227. char *ck_cmdline;
  228. char *name = "crashkernel=";
  229. BUG_ON(!crash_size || !crash_base);
  230. *crash_size = 0;
  231. *crash_base = 0;
  232. ck_cmdline = get_last_crashkernel(cmdline, name, suffix);
  233. if (!ck_cmdline)
  234. return -ENOENT;
  235. ck_cmdline += strlen(name);
  236. if (suffix)
  237. return parse_crashkernel_suffix(ck_cmdline, crash_size,
  238. suffix);
  239. /*
  240. * if the commandline contains a ':', then that's the extended
  241. * syntax -- if not, it must be the classic syntax
  242. */
  243. first_colon = strchr(ck_cmdline, ':');
  244. first_space = strchr(ck_cmdline, ' ');
  245. if (first_colon && (!first_space || first_colon < first_space))
  246. return parse_crashkernel_mem(ck_cmdline, system_ram,
  247. crash_size, crash_base);
  248. return parse_crashkernel_simple(ck_cmdline, crash_size, crash_base);
  249. }
  250. /*
  251. * That function is the entry point for command line parsing and should be
  252. * called from the arch-specific code.
  253. *
  254. * If crashkernel=,high|low is supported on architecture, non-NULL values
  255. * should be passed to parameters 'low_size' and 'high'.
  256. */
  257. int __init parse_crashkernel(char *cmdline,
  258. unsigned long long system_ram,
  259. unsigned long long *crash_size,
  260. unsigned long long *crash_base,
  261. unsigned long long *low_size,
  262. bool *high)
  263. {
  264. int ret;
  265. /* crashkernel=X[@offset] */
  266. ret = __parse_crashkernel(cmdline, system_ram, crash_size,
  267. crash_base, NULL);
  268. #ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
  269. /*
  270. * If non-NULL 'high' passed in and no normal crashkernel
  271. * setting detected, try parsing crashkernel=,high|low.
  272. */
  273. if (high && ret == -ENOENT) {
  274. ret = __parse_crashkernel(cmdline, 0, crash_size,
  275. crash_base, suffix_tbl[SUFFIX_HIGH]);
  276. if (ret || !*crash_size)
  277. return -EINVAL;
  278. /*
  279. * crashkernel=Y,low can be specified or not, but invalid value
  280. * is not allowed.
  281. */
  282. ret = __parse_crashkernel(cmdline, 0, low_size,
  283. crash_base, suffix_tbl[SUFFIX_LOW]);
  284. if (ret == -ENOENT) {
  285. *low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
  286. ret = 0;
  287. } else if (ret) {
  288. return ret;
  289. }
  290. *high = true;
  291. }
  292. #endif
  293. if (!*crash_size)
  294. ret = -EINVAL;
  295. if (*crash_size >= system_ram)
  296. ret = -EINVAL;
  297. return ret;
  298. }
  299. /*
  300. * Add a dummy early_param handler to mark crashkernel= as a known command line
  301. * parameter and suppress incorrect warnings in init/main.c.
  302. */
  303. static int __init parse_crashkernel_dummy(char *arg)
  304. {
  305. return 0;
  306. }
  307. early_param("crashkernel", parse_crashkernel_dummy);
  308. #ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
  309. static int __init reserve_crashkernel_low(unsigned long long low_size)
  310. {
  311. #ifdef CONFIG_64BIT
  312. unsigned long long low_base;
  313. low_base = memblock_phys_alloc_range(low_size, CRASH_ALIGN, 0, CRASH_ADDR_LOW_MAX);
  314. if (!low_base) {
  315. pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size);
  316. return -ENOMEM;
  317. }
  318. pr_info("crashkernel low memory reserved: 0x%08llx - 0x%08llx (%lld MB)\n",
  319. low_base, low_base + low_size, low_size >> 20);
  320. crashk_low_res.start = low_base;
  321. crashk_low_res.end = low_base + low_size - 1;
  322. #ifdef HAVE_ARCH_ADD_CRASH_RES_TO_IOMEM_EARLY
  323. insert_resource(&iomem_resource, &crashk_low_res);
  324. #endif
  325. #endif
  326. return 0;
  327. }
  328. void __init reserve_crashkernel_generic(char *cmdline,
  329. unsigned long long crash_size,
  330. unsigned long long crash_base,
  331. unsigned long long crash_low_size,
  332. bool high)
  333. {
  334. unsigned long long search_end = CRASH_ADDR_LOW_MAX, search_base = 0;
  335. bool fixed_base = false;
  336. /* User specifies base address explicitly. */
  337. if (crash_base) {
  338. fixed_base = true;
  339. search_base = crash_base;
  340. search_end = crash_base + crash_size;
  341. } else if (high) {
  342. search_base = CRASH_ADDR_LOW_MAX;
  343. search_end = CRASH_ADDR_HIGH_MAX;
  344. }
  345. retry:
  346. crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
  347. search_base, search_end);
  348. if (!crash_base) {
  349. /*
  350. * For crashkernel=size[KMG]@offset[KMG], print out failure
  351. * message if can't reserve the specified region.
  352. */
  353. if (fixed_base) {
  354. pr_warn("crashkernel reservation failed - memory is in use.\n");
  355. return;
  356. }
  357. /*
  358. * For crashkernel=size[KMG], if the first attempt was for
  359. * low memory, fall back to high memory, the minimum required
  360. * low memory will be reserved later.
  361. */
  362. if (!high && search_end == CRASH_ADDR_LOW_MAX) {
  363. search_end = CRASH_ADDR_HIGH_MAX;
  364. search_base = CRASH_ADDR_LOW_MAX;
  365. crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
  366. goto retry;
  367. }
  368. /*
  369. * For crashkernel=size[KMG],high, if the first attempt was
  370. * for high memory, fall back to low memory.
  371. */
  372. if (high && search_end == CRASH_ADDR_HIGH_MAX) {
  373. search_end = CRASH_ADDR_LOW_MAX;
  374. search_base = 0;
  375. if (search_end != CRASH_ADDR_HIGH_MAX)
  376. goto retry;
  377. }
  378. pr_warn("cannot allocate crashkernel (size:0x%llx)\n",
  379. crash_size);
  380. return;
  381. }
  382. if ((crash_base >= CRASH_ADDR_LOW_MAX) &&
  383. crash_low_size && reserve_crashkernel_low(crash_low_size)) {
  384. memblock_phys_free(crash_base, crash_size);
  385. return;
  386. }
  387. pr_info("crashkernel reserved: 0x%016llx - 0x%016llx (%lld MB)\n",
  388. crash_base, crash_base + crash_size, crash_size >> 20);
  389. /*
  390. * The crashkernel memory will be removed from the kernel linear
  391. * map. Inform kmemleak so that it won't try to access it.
  392. */
  393. kmemleak_ignore_phys(crash_base);
  394. if (crashk_low_res.end)
  395. kmemleak_ignore_phys(crashk_low_res.start);
  396. crashk_res.start = crash_base;
  397. crashk_res.end = crash_base + crash_size - 1;
  398. #ifdef HAVE_ARCH_ADD_CRASH_RES_TO_IOMEM_EARLY
  399. insert_resource(&iomem_resource, &crashk_res);
  400. #endif
  401. }
  402. #ifndef HAVE_ARCH_ADD_CRASH_RES_TO_IOMEM_EARLY
  403. static __init int insert_crashkernel_resources(void)
  404. {
  405. if (crashk_res.start < crashk_res.end)
  406. insert_resource(&iomem_resource, &crashk_res);
  407. if (crashk_low_res.start < crashk_low_res.end)
  408. insert_resource(&iomem_resource, &crashk_low_res);
  409. return 0;
  410. }
  411. early_initcall(insert_crashkernel_resources);
  412. #endif
  413. #endif