Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * fake_mem.c
0004  *
0005  * Copyright (C) 2015 FUJITSU LIMITED
0006  * Author: Taku Izumi <izumi.taku@jp.fujitsu.com>
0007  *
0008  * This code introduces new boot option named "efi_fake_mem"
0009  * By specifying this parameter, you can add arbitrary attribute to
0010  * specific memory range by updating original (firmware provided) EFI
0011  * memmap.
0012  */
0013 
0014 #include <linux/kernel.h>
0015 #include <linux/efi.h>
0016 #include <linux/init.h>
0017 #include <linux/memblock.h>
0018 #include <linux/types.h>
0019 #include <linux/sort.h>
0020 #include "fake_mem.h"
0021 
0022 struct efi_mem_range efi_fake_mems[EFI_MAX_FAKEMEM];
0023 int nr_fake_mem;
0024 
0025 static int __init cmp_fake_mem(const void *x1, const void *x2)
0026 {
0027     const struct efi_mem_range *m1 = x1;
0028     const struct efi_mem_range *m2 = x2;
0029 
0030     if (m1->range.start < m2->range.start)
0031         return -1;
0032     if (m1->range.start > m2->range.start)
0033         return 1;
0034     return 0;
0035 }
0036 
0037 static void __init efi_fake_range(struct efi_mem_range *efi_range)
0038 {
0039     struct efi_memory_map_data data = { 0 };
0040     int new_nr_map = efi.memmap.nr_map;
0041     efi_memory_desc_t *md;
0042     void *new_memmap;
0043 
0044     /* count up the number of EFI memory descriptor */
0045     for_each_efi_memory_desc(md)
0046         new_nr_map += efi_memmap_split_count(md, &efi_range->range);
0047 
0048     /* allocate memory for new EFI memmap */
0049     if (efi_memmap_alloc(new_nr_map, &data) != 0)
0050         return;
0051 
0052     /* create new EFI memmap */
0053     new_memmap = early_memremap(data.phys_map, data.size);
0054     if (!new_memmap) {
0055         __efi_memmap_free(data.phys_map, data.size, data.flags);
0056         return;
0057     }
0058 
0059     efi_memmap_insert(&efi.memmap, new_memmap, efi_range);
0060 
0061     /* swap into new EFI memmap */
0062     early_memunmap(new_memmap, data.size);
0063 
0064     efi_memmap_install(&data);
0065 }
0066 
0067 void __init efi_fake_memmap(void)
0068 {
0069     int i;
0070 
0071     if (!efi_enabled(EFI_MEMMAP) || !nr_fake_mem)
0072         return;
0073 
0074     for (i = 0; i < nr_fake_mem; i++)
0075         efi_fake_range(&efi_fake_mems[i]);
0076 
0077     /* print new EFI memmap */
0078     efi_print_memmap();
0079 }
0080 
0081 static int __init setup_fake_mem(char *p)
0082 {
0083     u64 start = 0, mem_size = 0, attribute = 0;
0084     int i;
0085 
0086     if (!p)
0087         return -EINVAL;
0088 
0089     while (*p != '\0') {
0090         mem_size = memparse(p, &p);
0091         if (*p == '@')
0092             start = memparse(p+1, &p);
0093         else
0094             break;
0095 
0096         if (*p == ':')
0097             attribute = simple_strtoull(p+1, &p, 0);
0098         else
0099             break;
0100 
0101         if (nr_fake_mem >= EFI_MAX_FAKEMEM)
0102             break;
0103 
0104         efi_fake_mems[nr_fake_mem].range.start = start;
0105         efi_fake_mems[nr_fake_mem].range.end = start + mem_size - 1;
0106         efi_fake_mems[nr_fake_mem].attribute = attribute;
0107         nr_fake_mem++;
0108 
0109         if (*p == ',')
0110             p++;
0111     }
0112 
0113     sort(efi_fake_mems, nr_fake_mem, sizeof(struct efi_mem_range),
0114          cmp_fake_mem, NULL);
0115 
0116     for (i = 0; i < nr_fake_mem; i++)
0117         pr_info("efi_fake_mem: add attr=0x%016llx to [mem 0x%016llx-0x%016llx]",
0118             efi_fake_mems[i].attribute, efi_fake_mems[i].range.start,
0119             efi_fake_mems[i].range.end);
0120 
0121     return *p == '\0' ? 0 : -EINVAL;
0122 }
0123 
0124 early_param("efi_fake_mem", setup_fake_mem);