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

fake_mem.c (2833B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * fake_mem.c
      4 *
      5 * Copyright (C) 2015 FUJITSU LIMITED
      6 * Author: Taku Izumi <izumi.taku@jp.fujitsu.com>
      7 *
      8 * This code introduces new boot option named "efi_fake_mem"
      9 * By specifying this parameter, you can add arbitrary attribute to
     10 * specific memory range by updating original (firmware provided) EFI
     11 * memmap.
     12 */
     13
     14#include <linux/kernel.h>
     15#include <linux/efi.h>
     16#include <linux/init.h>
     17#include <linux/memblock.h>
     18#include <linux/types.h>
     19#include <linux/sort.h>
     20#include "fake_mem.h"
     21
     22struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
     23int nr_fake_mem;
     24
     25static int __init cmp_fake_mem(const void *x1, const void *x2)
     26{
     27	const struct efi_mem_range *m1 = x1;
     28	const struct efi_mem_range *m2 = x2;
     29
     30	if (m1->range.start < m2->range.start)
     31		return -1;
     32	if (m1->range.start > m2->range.start)
     33		return 1;
     34	return 0;
     35}
     36
     37static void __init efi_fake_range(struct efi_mem_range *efi_range)
     38{
     39	struct efi_memory_map_data data = { 0 };
     40	int new_nr_map = efi.memmap.nr_map;
     41	efi_memory_desc_t *md;
     42	void *new_memmap;
     43
     44	/* count up the number of EFI memory descriptor */
     45	for_each_efi_memory_desc(md)
     46		new_nr_map += efi_memmap_split_count(md, &efi_range->range);
     47
     48	/* allocate memory for new EFI memmap */
     49	if (efi_memmap_alloc(new_nr_map, &data) != 0)
     50		return;
     51
     52	/* create new EFI memmap */
     53	new_memmap = early_memremap(data.phys_map, data.size);
     54	if (!new_memmap) {
     55		__efi_memmap_free(data.phys_map, data.size, data.flags);
     56		return;
     57	}
     58
     59	efi_memmap_insert(&efi.memmap, new_memmap, efi_range);
     60
     61	/* swap into new EFI memmap */
     62	early_memunmap(new_memmap, data.size);
     63
     64	efi_memmap_install(&data);
     65}
     66
     67void __init efi_fake_memmap(void)
     68{
     69	int i;
     70
     71	if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
     72		return;
     73
     74	for (i = 0; i < nr_fake_mem; i++)
     75		efi_fake_range(&efi_fake_mems[i]);
     76
     77	/* print new EFI memmap */
     78	efi_print_memmap();
     79}
     80
     81static int __init setup_fake_mem(char *p)
     82{
     83	u64 start = 0, mem_size = 0, attribute = 0;
     84	int i;
     85
     86	if (!p)
     87		return -EINVAL;
     88
     89	while (*p != '\0') {
     90		mem_size = memparse(p, &p);
     91		if (*p == '@')
     92			start = memparse(p+1, &p);
     93		else
     94			break;
     95
     96		if (*p == ':')
     97			attribute = simple_strtoull(p+1, &p, 0);
     98		else
     99			break;
    100
    101		if (nr_fake_mem >= EFI_MAX_FAKEMEM)
    102			break;
    103
    104		efi_fake_mems[nr_fake_mem].range.start = start;
    105		efi_fake_mems[nr_fake_mem].range.end = start + mem_size - 1;
    106		efi_fake_mems[nr_fake_mem].attribute = attribute;
    107		nr_fake_mem++;
    108
    109		if (*p == ',')
    110			p++;
    111	}
    112
    113	sort(efi_fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
    114	     cmp_fake_mem, NULL);
    115
    116	for (i = 0; i < nr_fake_mem; i++)
    117		pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]",
    118			efi_fake_mems[i].attribute, efi_fake_mems[i].range.start,
    119			efi_fake_mems[i].range.end);
    120
    121	return *p == '\0' ? 0 : -EINVAL;
    122}
    123
    124early_param("efi_fake_mem", setup_fake_mem);