cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ranges.c (10462B)


      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
     17#define pr_fmt(fmt) "kexec ranges: " fmt
     18
     19#include <linux/sort.h>
     20#include <linux/kexec.h>
     21#include <linux/of_device.h>
     22#include <linux/slab.h>
     23#include <asm/sections.h>
     24#include <asm/kexec_ranges.h>
     25
     26/**
     27 * get_max_nr_ranges - Get the max no. of ranges crash_mem structure
     28 *                     could hold, given the size allocated for it.
     29 * @size:              Allocation size of crash_mem structure.
     30 *
     31 * Returns the maximum no. of ranges.
     32 */
     33static inline unsigned int get_max_nr_ranges(size_t size)
     34{
     35	return ((size - sizeof(struct crash_mem)) /
     36		sizeof(struct crash_mem_range));
     37}
     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 */
     46static inline size_t get_mem_rngs_size(struct crash_mem *mem_rngs)
     47{
     48	size_t size;
     49
     50	if (!mem_rngs)
     51		return 0;
     52
     53	size = (sizeof(struct crash_mem) +
     54		(mem_rngs->max_nr_ranges * sizeof(struct crash_mem_range)));
     55
     56	/*
     57	 * Memory is allocated in size multiple of MEM_RANGE_CHUNK_SZ.
     58	 * So, align to get the actual length.
     59	 */
     60	return ALIGN(size, MEM_RANGE_CHUNK_SZ);
     61}
     62
     63/**
     64 * __add_mem_range - add a memory range to memory ranges list.
     65 * @mem_ranges:      Range list to add the memory range to.
     66 * @base:            Base address of the range to add.
     67 * @size:            Size of the memory range to add.
     68 *
     69 * (Re)allocates memory, if needed.
     70 *
     71 * Returns 0 on success, negative errno on error.
     72 */
     73static int __add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size)
     74{
     75	struct crash_mem *mem_rngs = *mem_ranges;
     76
     77	if (!mem_rngs || (mem_rngs->nr_ranges == mem_rngs->max_nr_ranges)) {
     78		mem_rngs = realloc_mem_ranges(mem_ranges);
     79		if (!mem_rngs)
     80			return -ENOMEM;
     81	}
     82
     83	mem_rngs->ranges[mem_rngs->nr_ranges].start = base;
     84	mem_rngs->ranges[mem_rngs->nr_ranges].end = base + size - 1;
     85	pr_debug("Added memory range [%#016llx - %#016llx] at index %d\n",
     86		 base, base + size - 1, mem_rngs->nr_ranges);
     87	mem_rngs->nr_ranges++;
     88	return 0;
     89}
     90
     91/**
     92 * __merge_memory_ranges - Merges the given memory ranges list.
     93 * @mem_rngs:              Range list to merge.
     94 *
     95 * Assumes a sorted range list.
     96 *
     97 * Returns nothing.
     98 */
     99static void __merge_memory_ranges(struct crash_mem *mem_rngs)
    100{
    101	struct crash_mem_range *ranges;
    102	int i, idx;
    103
    104	if (!mem_rngs)
    105		return;
    106
    107	idx = 0;
    108	ranges = &(mem_rngs->ranges[0]);
    109	for (i = 1; i < mem_rngs->nr_ranges; i++) {
    110		if (ranges[i].start <= (ranges[i-1].end + 1))
    111			ranges[idx].end = ranges[i].end;
    112		else {
    113			idx++;
    114			if (i == idx)
    115				continue;
    116
    117			ranges[idx] = ranges[i];
    118		}
    119	}
    120	mem_rngs->nr_ranges = idx + 1;
    121}
    122
    123/* cmp_func_t callback to sort ranges with sort() */
    124static int rngcmp(const void *_x, const void *_y)
    125{
    126	const struct crash_mem_range *x = _x, *y = _y;
    127
    128	if (x->start > y->start)
    129		return 1;
    130	if (x->start < y->start)
    131		return -1;
    132	return 0;
    133}
    134
    135/**
    136 * sort_memory_ranges - Sorts the given memory ranges list.
    137 * @mem_rngs:           Range list to sort.
    138 * @merge:              If true, merge the list after sorting.
    139 *
    140 * Returns nothing.
    141 */
    142void sort_memory_ranges(struct crash_mem *mem_rngs, bool merge)
    143{
    144	int i;
    145
    146	if (!mem_rngs)
    147		return;
    148
    149	/* Sort the ranges in-place */
    150	sort(&(mem_rngs->ranges[0]), mem_rngs->nr_ranges,
    151	     sizeof(mem_rngs->ranges[0]), rngcmp, NULL);
    152
    153	if (merge)
    154		__merge_memory_ranges(mem_rngs);
    155
    156	/* For debugging purpose */
    157	pr_debug("Memory ranges:\n");
    158	for (i = 0; i < mem_rngs->nr_ranges; i++) {
    159		pr_debug("\t[%03d][%#016llx - %#016llx]\n", i,
    160			 mem_rngs->ranges[i].start,
    161			 mem_rngs->ranges[i].end);
    162	}
    163}
    164
    165/**
    166 * realloc_mem_ranges - reallocate mem_ranges with size incremented
    167 *                      by MEM_RANGE_CHUNK_SZ. Frees up the old memory,
    168 *                      if memory allocation fails.
    169 * @mem_ranges:         Memory ranges to reallocate.
    170 *
    171 * Returns pointer to reallocated memory on success, NULL otherwise.
    172 */
    173struct crash_mem *realloc_mem_ranges(struct crash_mem **mem_ranges)
    174{
    175	struct crash_mem *mem_rngs = *mem_ranges;
    176	unsigned int nr_ranges;
    177	size_t size;
    178
    179	size = get_mem_rngs_size(mem_rngs);
    180	nr_ranges = mem_rngs ? mem_rngs->nr_ranges : 0;
    181
    182	size += MEM_RANGE_CHUNK_SZ;
    183	mem_rngs = krealloc(*mem_ranges, size, GFP_KERNEL);
    184	if (!mem_rngs) {
    185		kfree(*mem_ranges);
    186		*mem_ranges = NULL;
    187		return NULL;
    188	}
    189
    190	mem_rngs->nr_ranges = nr_ranges;
    191	mem_rngs->max_nr_ranges = get_max_nr_ranges(size);
    192	*mem_ranges = mem_rngs;
    193
    194	return mem_rngs;
    195}
    196
    197/**
    198 * add_mem_range - Updates existing memory range, if there is an overlap.
    199 *                 Else, adds a new memory range.
    200 * @mem_ranges:    Range list to add the memory range to.
    201 * @base:          Base address of the range to add.
    202 * @size:          Size of the memory range to add.
    203 *
    204 * (Re)allocates memory, if needed.
    205 *
    206 * Returns 0 on success, negative errno on error.
    207 */
    208int add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size)
    209{
    210	struct crash_mem *mem_rngs = *mem_ranges;
    211	u64 mstart, mend, end;
    212	unsigned int i;
    213
    214	if (!size)
    215		return 0;
    216
    217	end = base + size - 1;
    218
    219	if (!mem_rngs || !(mem_rngs->nr_ranges))
    220		return __add_mem_range(mem_ranges, base, size);
    221
    222	for (i = 0; i < mem_rngs->nr_ranges; i++) {
    223		mstart = mem_rngs->ranges[i].start;
    224		mend = mem_rngs->ranges[i].end;
    225		if (base < mend && end > mstart) {
    226			if (base < mstart)
    227				mem_rngs->ranges[i].start = base;
    228			if (end > mend)
    229				mem_rngs->ranges[i].end = end;
    230			return 0;
    231		}
    232	}
    233
    234	return __add_mem_range(mem_ranges, base, size);
    235}
    236
    237/**
    238 * add_tce_mem_ranges - Adds tce-table range to the given memory ranges list.
    239 * @mem_ranges:         Range list to add the memory range(s) to.
    240 *
    241 * Returns 0 on success, negative errno on error.
    242 */
    243int add_tce_mem_ranges(struct crash_mem **mem_ranges)
    244{
    245	struct device_node *dn = NULL;
    246	int ret = 0;
    247
    248	for_each_node_by_type(dn, "pci") {
    249		u64 base;
    250		u32 size;
    251
    252		ret = of_property_read_u64(dn, "linux,tce-base", &base);
    253		ret |= of_property_read_u32(dn, "linux,tce-size", &size);
    254		if (ret) {
    255			/*
    256			 * It is ok to have pci nodes without tce. So, ignore
    257			 * property does not exist error.
    258			 */
    259			if (ret == -EINVAL) {
    260				ret = 0;
    261				continue;
    262			}
    263			break;
    264		}
    265
    266		ret = add_mem_range(mem_ranges, base, size);
    267		if (ret)
    268			break;
    269	}
    270
    271	of_node_put(dn);
    272	return ret;
    273}
    274
    275/**
    276 * add_initrd_mem_range - Adds initrd range to the given memory ranges list,
    277 *                        if the initrd was retained.
    278 * @mem_ranges:           Range list to add the memory range to.
    279 *
    280 * Returns 0 on success, negative errno on error.
    281 */
    282int add_initrd_mem_range(struct crash_mem **mem_ranges)
    283{
    284	u64 base, end;
    285	int ret;
    286
    287	/* This range means something, only if initrd was retained */
    288	if (!strstr(saved_command_line, "retain_initrd"))
    289		return 0;
    290
    291	ret = of_property_read_u64(of_chosen, "linux,initrd-start", &base);
    292	ret |= of_property_read_u64(of_chosen, "linux,initrd-end", &end);
    293	if (!ret)
    294		ret = add_mem_range(mem_ranges, base, end - base + 1);
    295
    296	return ret;
    297}
    298
    299#ifdef CONFIG_PPC_64S_HASH_MMU
    300/**
    301 * add_htab_mem_range - Adds htab range to the given memory ranges list,
    302 *                      if it exists
    303 * @mem_ranges:         Range list to add the memory range to.
    304 *
    305 * Returns 0 on success, negative errno on error.
    306 */
    307int add_htab_mem_range(struct crash_mem **mem_ranges)
    308{
    309	if (!htab_address)
    310		return 0;
    311
    312	return add_mem_range(mem_ranges, __pa(htab_address), htab_size_bytes);
    313}
    314#endif
    315
    316/**
    317 * add_kernel_mem_range - Adds kernel text region to the given
    318 *                        memory ranges list.
    319 * @mem_ranges:           Range list to add the memory range to.
    320 *
    321 * Returns 0 on success, negative errno on error.
    322 */
    323int add_kernel_mem_range(struct crash_mem **mem_ranges)
    324{
    325	return add_mem_range(mem_ranges, 0, __pa(_end));
    326}
    327
    328/**
    329 * add_rtas_mem_range - Adds RTAS region to the given memory ranges list.
    330 * @mem_ranges:         Range list to add the memory range to.
    331 *
    332 * Returns 0 on success, negative errno on error.
    333 */
    334int add_rtas_mem_range(struct crash_mem **mem_ranges)
    335{
    336	struct device_node *dn;
    337	u32 base, size;
    338	int ret = 0;
    339
    340	dn = of_find_node_by_path("/rtas");
    341	if (!dn)
    342		return 0;
    343
    344	ret = of_property_read_u32(dn, "linux,rtas-base", &base);
    345	ret |= of_property_read_u32(dn, "rtas-size", &size);
    346	if (!ret)
    347		ret = add_mem_range(mem_ranges, base, size);
    348
    349	of_node_put(dn);
    350	return ret;
    351}
    352
    353/**
    354 * add_opal_mem_range - Adds OPAL region to the given memory ranges list.
    355 * @mem_ranges:         Range list to add the memory range to.
    356 *
    357 * Returns 0 on success, negative errno on error.
    358 */
    359int add_opal_mem_range(struct crash_mem **mem_ranges)
    360{
    361	struct device_node *dn;
    362	u64 base, size;
    363	int ret;
    364
    365	dn = of_find_node_by_path("/ibm,opal");
    366	if (!dn)
    367		return 0;
    368
    369	ret = of_property_read_u64(dn, "opal-base-address", &base);
    370	ret |= of_property_read_u64(dn, "opal-runtime-size", &size);
    371	if (!ret)
    372		ret = add_mem_range(mem_ranges, base, size);
    373
    374	of_node_put(dn);
    375	return ret;
    376}
    377
    378/**
    379 * add_reserved_mem_ranges - Adds "/reserved-ranges" regions exported by f/w
    380 *                           to the given memory ranges list.
    381 * @mem_ranges:              Range list to add the memory ranges to.
    382 *
    383 * Returns 0 on success, negative errno on error.
    384 */
    385int add_reserved_mem_ranges(struct crash_mem **mem_ranges)
    386{
    387	int n_mem_addr_cells, n_mem_size_cells, i, len, cells, ret = 0;
    388	const __be32 *prop;
    389
    390	prop = of_get_property(of_root, "reserved-ranges", &len);
    391	if (!prop)
    392		return 0;
    393
    394	n_mem_addr_cells = of_n_addr_cells(of_root);
    395	n_mem_size_cells = of_n_size_cells(of_root);
    396	cells = n_mem_addr_cells + n_mem_size_cells;
    397
    398	/* Each reserved range is an (address,size) pair */
    399	for (i = 0; i < (len / (sizeof(u32) * cells)); i++) {
    400		u64 base, size;
    401
    402		base = of_read_number(prop + (i * cells), n_mem_addr_cells);
    403		size = of_read_number(prop + (i * cells) + n_mem_addr_cells,
    404				      n_mem_size_cells);
    405
    406		ret = add_mem_range(mem_ranges, base, size);
    407		if (ret)
    408			break;
    409	}
    410
    411	return ret;
    412}