ranges.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * powerpc code to implement the kexec_file_load syscall
  4. *
  5. * Copyright (C) 2004 Adam Litke (agl@us.ibm.com)
  6. * Copyright (C) 2004 IBM Corp.
  7. * Copyright (C) 2004,2005 Milton D Miller II, IBM Corporation
  8. * Copyright (C) 2005 R Sharada (sharada@in.ibm.com)
  9. * Copyright (C) 2006 Mohan Kumar M (mohan@in.ibm.com)
  10. * Copyright (C) 2020 IBM Corporation
  11. *
  12. * Based on kexec-tools' kexec-ppc64.c, fs2dt.c.
  13. * Heavily modified for the kernel by
  14. * Hari Bathini, IBM Corporation.
  15. */
  16. #define pr_fmt(fmt) "kexec ranges: " fmt
  17. #include <linux/sort.h>
  18. #include <linux/kexec.h>
  19. #include <linux/of.h>
  20. #include <linux/slab.h>
  21. #include <linux/memblock.h>
  22. #include <linux/crash_core.h>
  23. #include <asm/sections.h>
  24. #include <asm/kexec_ranges.h>
  25. #include <asm/crashdump-ppc64.h>
  26. #if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_DUMP)
  27. /**
  28. * get_max_nr_ranges - Get the max no. of ranges crash_mem structure
  29. * could hold, given the size allocated for it.
  30. * @size: Allocation size of crash_mem structure.
  31. *
  32. * Returns the maximum no. of ranges.
  33. */
  34. static inline unsigned int get_max_nr_ranges(size_t size)
  35. {
  36. return ((size - sizeof(struct crash_mem)) /
  37. sizeof(struct range));
  38. }
  39. /**
  40. * get_mem_rngs_size - Get the allocated size of mem_rngs based on
  41. * max_nr_ranges and chunk size.
  42. * @mem_rngs: Memory ranges.
  43. *
  44. * Returns the maximum size of @mem_rngs.
  45. */
  46. static inline size_t get_mem_rngs_size(struct crash_mem *mem_rngs)
  47. {
  48. size_t size;
  49. if (!mem_rngs)
  50. return 0;
  51. size = (sizeof(struct crash_mem) +
  52. (mem_rngs->max_nr_ranges * sizeof(struct range)));
  53. /*
  54. * Memory is allocated in size multiple of MEM_RANGE_CHUNK_SZ.
  55. * So, align to get the actual length.
  56. */
  57. return ALIGN(size, MEM_RANGE_CHUNK_SZ);
  58. }
  59. /**
  60. * __add_mem_range - add a memory range to memory ranges list.
  61. * @mem_ranges: Range list to add the memory range to.
  62. * @base: Base address of the range to add.
  63. * @size: Size of the memory range to add.
  64. *
  65. * (Re)allocates memory, if needed.
  66. *
  67. * Returns 0 on success, negative errno on error.
  68. */
  69. static int __add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size)
  70. {
  71. struct crash_mem *mem_rngs = *mem_ranges;
  72. if (!mem_rngs || (mem_rngs->nr_ranges == mem_rngs->max_nr_ranges)) {
  73. mem_rngs = realloc_mem_ranges(mem_ranges);
  74. if (!mem_rngs)
  75. return -ENOMEM;
  76. }
  77. mem_rngs->ranges[mem_rngs->nr_ranges].start = base;
  78. mem_rngs->ranges[mem_rngs->nr_ranges].end = base + size - 1;
  79. pr_debug("Added memory range [%#016llx - %#016llx] at index %d\n",
  80. base, base + size - 1, mem_rngs->nr_ranges);
  81. mem_rngs->nr_ranges++;
  82. return 0;
  83. }
  84. /**
  85. * __merge_memory_ranges - Merges the given memory ranges list.
  86. * @mem_rngs: Range list to merge.
  87. *
  88. * Assumes a sorted range list.
  89. *
  90. * Returns nothing.
  91. */
  92. static void __merge_memory_ranges(struct crash_mem *mem_rngs)
  93. {
  94. struct range *ranges;
  95. int i, idx;
  96. if (!mem_rngs)
  97. return;
  98. idx = 0;
  99. ranges = &(mem_rngs->ranges[0]);
  100. for (i = 1; i < mem_rngs->nr_ranges; i++) {
  101. if (ranges[i].start <= (ranges[i-1].end + 1))
  102. ranges[idx].end = ranges[i].end;
  103. else {
  104. idx++;
  105. if (i == idx)
  106. continue;
  107. ranges[idx] = ranges[i];
  108. }
  109. }
  110. mem_rngs->nr_ranges = idx + 1;
  111. }
  112. /* cmp_func_t callback to sort ranges with sort() */
  113. static int rngcmp(const void *_x, const void *_y)
  114. {
  115. const struct range *x = _x, *y = _y;
  116. if (x->start > y->start)
  117. return 1;
  118. if (x->start < y->start)
  119. return -1;
  120. return 0;
  121. }
  122. /**
  123. * sort_memory_ranges - Sorts the given memory ranges list.
  124. * @mem_rngs: Range list to sort.
  125. * @merge: If true, merge the list after sorting.
  126. *
  127. * Returns nothing.
  128. */
  129. void sort_memory_ranges(struct crash_mem *mem_rngs, bool merge)
  130. {
  131. int i;
  132. if (!mem_rngs)
  133. return;
  134. /* Sort the ranges in-place */
  135. sort(&(mem_rngs->ranges[0]), mem_rngs->nr_ranges,
  136. sizeof(mem_rngs->ranges[0]), rngcmp, NULL);
  137. if (merge)
  138. __merge_memory_ranges(mem_rngs);
  139. /* For debugging purpose */
  140. pr_debug("Memory ranges:\n");
  141. for (i = 0; i < mem_rngs->nr_ranges; i++) {
  142. pr_debug("\t[%03d][%#016llx - %#016llx]\n", i,
  143. mem_rngs->ranges[i].start,
  144. mem_rngs->ranges[i].end);
  145. }
  146. }
  147. /**
  148. * realloc_mem_ranges - reallocate mem_ranges with size incremented
  149. * by MEM_RANGE_CHUNK_SZ. Frees up the old memory,
  150. * if memory allocation fails.
  151. * @mem_ranges: Memory ranges to reallocate.
  152. *
  153. * Returns pointer to reallocated memory on success, NULL otherwise.
  154. */
  155. struct crash_mem *realloc_mem_ranges(struct crash_mem **mem_ranges)
  156. {
  157. struct crash_mem *mem_rngs = *mem_ranges;
  158. unsigned int nr_ranges;
  159. size_t size;
  160. size = get_mem_rngs_size(mem_rngs);
  161. nr_ranges = mem_rngs ? mem_rngs->nr_ranges : 0;
  162. size += MEM_RANGE_CHUNK_SZ;
  163. mem_rngs = krealloc(*mem_ranges, size, GFP_KERNEL);
  164. if (!mem_rngs) {
  165. kfree(*mem_ranges);
  166. *mem_ranges = NULL;
  167. return NULL;
  168. }
  169. mem_rngs->nr_ranges = nr_ranges;
  170. mem_rngs->max_nr_ranges = get_max_nr_ranges(size);
  171. *mem_ranges = mem_rngs;
  172. return mem_rngs;
  173. }
  174. /**
  175. * add_mem_range - Updates existing memory range, if there is an overlap.
  176. * Else, adds a new memory range.
  177. * @mem_ranges: Range list to add the memory range to.
  178. * @base: Base address of the range to add.
  179. * @size: Size of the memory range to add.
  180. *
  181. * (Re)allocates memory, if needed.
  182. *
  183. * Returns 0 on success, negative errno on error.
  184. */
  185. int add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size)
  186. {
  187. struct crash_mem *mem_rngs = *mem_ranges;
  188. u64 mstart, mend, end;
  189. unsigned int i;
  190. if (!size)
  191. return 0;
  192. end = base + size - 1;
  193. if (!mem_rngs || !(mem_rngs->nr_ranges))
  194. return __add_mem_range(mem_ranges, base, size);
  195. for (i = 0; i < mem_rngs->nr_ranges; i++) {
  196. mstart = mem_rngs->ranges[i].start;
  197. mend = mem_rngs->ranges[i].end;
  198. if (base < mend && end > mstart) {
  199. if (base < mstart)
  200. mem_rngs->ranges[i].start = base;
  201. if (end > mend)
  202. mem_rngs->ranges[i].end = end;
  203. return 0;
  204. }
  205. }
  206. return __add_mem_range(mem_ranges, base, size);
  207. }
  208. #endif /* CONFIG_KEXEC_FILE || CONFIG_CRASH_DUMP */
  209. #ifdef CONFIG_KEXEC_FILE
  210. /**
  211. * add_tce_mem_ranges - Adds tce-table range to the given memory ranges list.
  212. * @mem_ranges: Range list to add the memory range(s) to.
  213. *
  214. * Returns 0 on success, negative errno on error.
  215. */
  216. static int add_tce_mem_ranges(struct crash_mem **mem_ranges)
  217. {
  218. struct device_node *dn = NULL;
  219. int ret = 0;
  220. for_each_node_by_type(dn, "pci") {
  221. u64 base;
  222. u32 size;
  223. ret = of_property_read_u64(dn, "linux,tce-base", &base);
  224. ret |= of_property_read_u32(dn, "linux,tce-size", &size);
  225. if (ret) {
  226. /*
  227. * It is ok to have pci nodes without tce. So, ignore
  228. * property does not exist error.
  229. */
  230. if (ret == -EINVAL) {
  231. ret = 0;
  232. continue;
  233. }
  234. break;
  235. }
  236. ret = add_mem_range(mem_ranges, base, size);
  237. if (ret)
  238. break;
  239. }
  240. of_node_put(dn);
  241. return ret;
  242. }
  243. /**
  244. * add_initrd_mem_range - Adds initrd range to the given memory ranges list,
  245. * if the initrd was retained.
  246. * @mem_ranges: Range list to add the memory range to.
  247. *
  248. * Returns 0 on success, negative errno on error.
  249. */
  250. static int add_initrd_mem_range(struct crash_mem **mem_ranges)
  251. {
  252. u64 base, end;
  253. int ret;
  254. /* This range means something, only if initrd was retained */
  255. if (!strstr(saved_command_line, "retain_initrd"))
  256. return 0;
  257. ret = of_property_read_u64(of_chosen, "linux,initrd-start", &base);
  258. ret |= of_property_read_u64(of_chosen, "linux,initrd-end", &end);
  259. if (!ret)
  260. ret = add_mem_range(mem_ranges, base, end - base + 1);
  261. return ret;
  262. }
  263. /**
  264. * add_htab_mem_range - Adds htab range to the given memory ranges list,
  265. * if it exists
  266. * @mem_ranges: Range list to add the memory range to.
  267. *
  268. * Returns 0 on success, negative errno on error.
  269. */
  270. static int add_htab_mem_range(struct crash_mem **mem_ranges)
  271. {
  272. #ifdef CONFIG_PPC_64S_HASH_MMU
  273. if (!htab_address)
  274. return 0;
  275. return add_mem_range(mem_ranges, __pa(htab_address), htab_size_bytes);
  276. #else
  277. return 0;
  278. #endif
  279. }
  280. /**
  281. * add_kernel_mem_range - Adds kernel text region to the given
  282. * memory ranges list.
  283. * @mem_ranges: Range list to add the memory range to.
  284. *
  285. * Returns 0 on success, negative errno on error.
  286. */
  287. static int add_kernel_mem_range(struct crash_mem **mem_ranges)
  288. {
  289. return add_mem_range(mem_ranges, 0, __pa(_end));
  290. }
  291. #endif /* CONFIG_KEXEC_FILE */
  292. #if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_DUMP)
  293. /**
  294. * add_rtas_mem_range - Adds RTAS region to the given memory ranges list.
  295. * @mem_ranges: Range list to add the memory range to.
  296. *
  297. * Returns 0 on success, negative errno on error.
  298. */
  299. static int add_rtas_mem_range(struct crash_mem **mem_ranges)
  300. {
  301. struct device_node *dn;
  302. u32 base, size;
  303. int ret = 0;
  304. dn = of_find_node_by_path("/rtas");
  305. if (!dn)
  306. return 0;
  307. ret = of_property_read_u32(dn, "linux,rtas-base", &base);
  308. ret |= of_property_read_u32(dn, "rtas-size", &size);
  309. if (!ret)
  310. ret = add_mem_range(mem_ranges, base, size);
  311. of_node_put(dn);
  312. return ret;
  313. }
  314. /**
  315. * add_opal_mem_range - Adds OPAL region to the given memory ranges list.
  316. * @mem_ranges: Range list to add the memory range to.
  317. *
  318. * Returns 0 on success, negative errno on error.
  319. */
  320. static int add_opal_mem_range(struct crash_mem **mem_ranges)
  321. {
  322. struct device_node *dn;
  323. u64 base, size;
  324. int ret;
  325. dn = of_find_node_by_path("/ibm,opal");
  326. if (!dn)
  327. return 0;
  328. ret = of_property_read_u64(dn, "opal-base-address", &base);
  329. ret |= of_property_read_u64(dn, "opal-runtime-size", &size);
  330. if (!ret)
  331. ret = add_mem_range(mem_ranges, base, size);
  332. of_node_put(dn);
  333. return ret;
  334. }
  335. #endif /* CONFIG_KEXEC_FILE || CONFIG_CRASH_DUMP */
  336. #ifdef CONFIG_KEXEC_FILE
  337. /**
  338. * add_reserved_mem_ranges - Adds "/reserved-ranges" regions exported by f/w
  339. * to the given memory ranges list.
  340. * @mem_ranges: Range list to add the memory ranges to.
  341. *
  342. * Returns 0 on success, negative errno on error.
  343. */
  344. static int add_reserved_mem_ranges(struct crash_mem **mem_ranges)
  345. {
  346. int n_mem_addr_cells, n_mem_size_cells, i, len, cells, ret = 0;
  347. struct device_node *root = of_find_node_by_path("/");
  348. const __be32 *prop;
  349. prop = of_get_property(root, "reserved-ranges", &len);
  350. n_mem_addr_cells = of_n_addr_cells(root);
  351. n_mem_size_cells = of_n_size_cells(root);
  352. of_node_put(root);
  353. if (!prop)
  354. return 0;
  355. cells = n_mem_addr_cells + n_mem_size_cells;
  356. /* Each reserved range is an (address,size) pair */
  357. for (i = 0; i < (len / (sizeof(u32) * cells)); i++) {
  358. u64 base, size;
  359. base = of_read_number(prop + (i * cells), n_mem_addr_cells);
  360. size = of_read_number(prop + (i * cells) + n_mem_addr_cells,
  361. n_mem_size_cells);
  362. ret = add_mem_range(mem_ranges, base, size);
  363. if (ret)
  364. break;
  365. }
  366. return ret;
  367. }
  368. /**
  369. * get_reserved_memory_ranges - Get reserve memory ranges. This list includes
  370. * memory regions that should be added to the
  371. * memory reserve map to ensure the region is
  372. * protected from any mischief.
  373. * @mem_ranges: Range list to add the memory ranges to.
  374. *
  375. * Returns 0 on success, negative errno on error.
  376. */
  377. int get_reserved_memory_ranges(struct crash_mem **mem_ranges)
  378. {
  379. int ret;
  380. ret = add_rtas_mem_range(mem_ranges);
  381. if (ret)
  382. goto out;
  383. ret = add_tce_mem_ranges(mem_ranges);
  384. if (ret)
  385. goto out;
  386. ret = add_reserved_mem_ranges(mem_ranges);
  387. out:
  388. if (ret)
  389. pr_err("Failed to setup reserved memory ranges\n");
  390. return ret;
  391. }
  392. /**
  393. * get_exclude_memory_ranges - Get exclude memory ranges. This list includes
  394. * regions like opal/rtas, tce-table, initrd,
  395. * kernel, htab which should be avoided while
  396. * setting up kexec load segments.
  397. * @mem_ranges: Range list to add the memory ranges to.
  398. *
  399. * Returns 0 on success, negative errno on error.
  400. */
  401. int get_exclude_memory_ranges(struct crash_mem **mem_ranges)
  402. {
  403. int ret;
  404. ret = add_tce_mem_ranges(mem_ranges);
  405. if (ret)
  406. goto out;
  407. ret = add_initrd_mem_range(mem_ranges);
  408. if (ret)
  409. goto out;
  410. ret = add_htab_mem_range(mem_ranges);
  411. if (ret)
  412. goto out;
  413. ret = add_kernel_mem_range(mem_ranges);
  414. if (ret)
  415. goto out;
  416. ret = add_rtas_mem_range(mem_ranges);
  417. if (ret)
  418. goto out;
  419. ret = add_opal_mem_range(mem_ranges);
  420. if (ret)
  421. goto out;
  422. ret = add_reserved_mem_ranges(mem_ranges);
  423. if (ret)
  424. goto out;
  425. /* exclude memory ranges should be sorted for easy lookup */
  426. sort_memory_ranges(*mem_ranges, true);
  427. out:
  428. if (ret)
  429. pr_err("Failed to setup exclude memory ranges\n");
  430. return ret;
  431. }
  432. #ifdef CONFIG_CRASH_DUMP
  433. /**
  434. * get_usable_memory_ranges - Get usable memory ranges. This list includes
  435. * regions like crashkernel, opal/rtas & tce-table,
  436. * that kdump kernel could use.
  437. * @mem_ranges: Range list to add the memory ranges to.
  438. *
  439. * Returns 0 on success, negative errno on error.
  440. */
  441. int get_usable_memory_ranges(struct crash_mem **mem_ranges)
  442. {
  443. int ret, i;
  444. /*
  445. * Early boot failure observed on guests when low memory (first memory
  446. * block?) is not added to usable memory. So, add [0, crashk_res.end]
  447. * instead of [crashk_res.start, crashk_res.end] to workaround it.
  448. * Also, crashed kernel's memory must be added to reserve map to
  449. * avoid kdump kernel from using it.
  450. */
  451. ret = add_mem_range(mem_ranges, 0, crashk_res.end + 1);
  452. if (ret)
  453. goto out;
  454. for (i = 0; i < crashk_cma_cnt; i++) {
  455. ret = add_mem_range(mem_ranges, crashk_cma_ranges[i].start,
  456. crashk_cma_ranges[i].end - crashk_cma_ranges[i].start + 1);
  457. if (ret)
  458. goto out;
  459. }
  460. ret = add_rtas_mem_range(mem_ranges);
  461. if (ret)
  462. goto out;
  463. ret = add_opal_mem_range(mem_ranges);
  464. if (ret)
  465. goto out;
  466. ret = add_tce_mem_ranges(mem_ranges);
  467. out:
  468. if (ret)
  469. pr_err("Failed to setup usable memory ranges\n");
  470. return ret;
  471. }
  472. #endif /* CONFIG_CRASH_DUMP */
  473. #endif /* CONFIG_KEXEC_FILE */
  474. #ifdef CONFIG_CRASH_DUMP
  475. static int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
  476. unsigned long long mstart,
  477. unsigned long long mend)
  478. {
  479. struct crash_mem *tmem = *mem_ranges;
  480. /* Reallocate memory ranges if there is no space to split ranges */
  481. if (tmem && (tmem->nr_ranges == tmem->max_nr_ranges)) {
  482. tmem = realloc_mem_ranges(mem_ranges);
  483. if (!tmem)
  484. return -ENOMEM;
  485. }
  486. return crash_exclude_mem_range(tmem, mstart, mend);
  487. }
  488. /**
  489. * get_crash_memory_ranges - Get crash memory ranges. This list includes
  490. * first/crashing kernel's memory regions that
  491. * would be exported via an elfcore.
  492. * @mem_ranges: Range list to add the memory ranges to.
  493. *
  494. * Returns 0 on success, negative errno on error.
  495. */
  496. int get_crash_memory_ranges(struct crash_mem **mem_ranges)
  497. {
  498. phys_addr_t base, end;
  499. u64 i;
  500. int ret;
  501. for_each_mem_range(i, &base, &end) {
  502. u64 size = end - base;
  503. /* Skip backup memory region, which needs a separate entry */
  504. if (base == BACKUP_SRC_START) {
  505. if (size > BACKUP_SRC_SIZE) {
  506. base = BACKUP_SRC_END + 1;
  507. size -= BACKUP_SRC_SIZE;
  508. } else
  509. continue;
  510. }
  511. ret = add_mem_range(mem_ranges, base, size);
  512. if (ret)
  513. goto out;
  514. /* Try merging adjacent ranges before reallocation attempt */
  515. if ((*mem_ranges)->nr_ranges == (*mem_ranges)->max_nr_ranges)
  516. sort_memory_ranges(*mem_ranges, true);
  517. }
  518. /* Exclude crashkernel region */
  519. ret = crash_exclude_mem_range_guarded(mem_ranges, crashk_res.start, crashk_res.end);
  520. if (ret)
  521. goto out;
  522. for (i = 0; i < crashk_cma_cnt; ++i) {
  523. ret = crash_exclude_mem_range_guarded(mem_ranges, crashk_cma_ranges[i].start,
  524. crashk_cma_ranges[i].end);
  525. if (ret)
  526. goto out;
  527. }
  528. /*
  529. * FIXME: For now, stay in parity with kexec-tools but if RTAS/OPAL
  530. * regions are exported to save their context at the time of
  531. * crash, they should actually be backed up just like the
  532. * first 64K bytes of memory.
  533. */
  534. ret = add_rtas_mem_range(mem_ranges);
  535. if (ret)
  536. goto out;
  537. ret = add_opal_mem_range(mem_ranges);
  538. if (ret)
  539. goto out;
  540. /* create a separate program header for the backup region */
  541. ret = add_mem_range(mem_ranges, BACKUP_SRC_START, BACKUP_SRC_SIZE);
  542. if (ret)
  543. goto out;
  544. sort_memory_ranges(*mem_ranges, false);
  545. out:
  546. if (ret)
  547. pr_err("Failed to setup crash memory ranges\n");
  548. return ret;
  549. }
  550. /**
  551. * remove_mem_range - Removes the given memory range from the range list.
  552. * @mem_ranges: Range list to remove the memory range to.
  553. * @base: Base address of the range to remove.
  554. * @size: Size of the memory range to remove.
  555. *
  556. * (Re)allocates memory, if needed.
  557. *
  558. * Returns 0 on success, negative errno on error.
  559. */
  560. int remove_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size)
  561. {
  562. u64 end;
  563. int ret = 0;
  564. unsigned int i;
  565. u64 mstart, mend;
  566. struct crash_mem *mem_rngs = *mem_ranges;
  567. if (!size)
  568. return 0;
  569. /*
  570. * Memory range are stored as start and end address, use
  571. * the same format to do remove operation.
  572. */
  573. end = base + size - 1;
  574. for (i = 0; i < mem_rngs->nr_ranges; i++) {
  575. mstart = mem_rngs->ranges[i].start;
  576. mend = mem_rngs->ranges[i].end;
  577. /*
  578. * Memory range to remove is not part of this range entry
  579. * in the memory range list
  580. */
  581. if (!(base >= mstart && end <= mend))
  582. continue;
  583. /*
  584. * Memory range to remove is equivalent to this entry in the
  585. * memory range list. Remove the range entry from the list.
  586. */
  587. if (base == mstart && end == mend) {
  588. for (; i < mem_rngs->nr_ranges - 1; i++) {
  589. mem_rngs->ranges[i].start = mem_rngs->ranges[i+1].start;
  590. mem_rngs->ranges[i].end = mem_rngs->ranges[i+1].end;
  591. }
  592. mem_rngs->nr_ranges--;
  593. goto out;
  594. }
  595. /*
  596. * Start address of the memory range to remove and the
  597. * current memory range entry in the list is same. Just
  598. * move the start address of the current memory range
  599. * entry in the list to end + 1.
  600. */
  601. else if (base == mstart) {
  602. mem_rngs->ranges[i].start = end + 1;
  603. goto out;
  604. }
  605. /*
  606. * End address of the memory range to remove and the
  607. * current memory range entry in the list is same.
  608. * Just move the end address of the current memory
  609. * range entry in the list to base - 1.
  610. */
  611. else if (end == mend) {
  612. mem_rngs->ranges[i].end = base - 1;
  613. goto out;
  614. }
  615. /*
  616. * Memory range to remove is not at the edge of current
  617. * memory range entry. Split the current memory entry into
  618. * two half.
  619. */
  620. else {
  621. size = mem_rngs->ranges[i].end - end + 1;
  622. mem_rngs->ranges[i].end = base - 1;
  623. ret = add_mem_range(mem_ranges, end + 1, size);
  624. }
  625. }
  626. out:
  627. return ret;
  628. }
  629. #endif /* CONFIG_CRASH_DUMP */