1 // SPDX-License-Identifier: GPL-2.0-or-later 2 #include "tests/common.h" 3 #include <string.h> 4 #include <getopt.h> 5 #include <linux/memory_hotplug.h> 6 #include <linux/build_bug.h> 7 8 #define INIT_MEMBLOCK_REGIONS 128 9 #define INIT_MEMBLOCK_RESERVED_REGIONS INIT_MEMBLOCK_REGIONS 10 #define PREFIXES_MAX 15 11 #define DELIM ": " 12 #define BASIS 10000 13 14 static struct test_memory memory_block; 15 static const char __maybe_unused *prefixes[PREFIXES_MAX]; 16 static int __maybe_unused nr_prefixes; 17 18 static const char *short_opts = "hmv"; 19 static const struct option long_opts[] = { 20 {"help", 0, NULL, 'h'}, 21 {"movable-node", 0, NULL, 'm'}, 22 {"verbose", 0, NULL, 'v'}, 23 {NULL, 0, NULL, 0} 24 }; 25 26 static const char * const help_opts[] = { 27 "display this help message and exit", 28 "disallow allocations from regions marked as hotplugged\n\t\t\t" 29 "by simulating enabling the \"movable_node\" kernel\n\t\t\t" 30 "parameter", 31 "enable verbose output, which includes the name of the\n\t\t\t" 32 "memblock function being tested, the name of the test,\n\t\t\t" 33 "and whether the test passed or failed." 34 }; 35 36 static int verbose; 37 38 /* sets global variable returned by movable_node_is_enabled() stub */ 39 bool movable_node_enabled; 40 41 void reset_memblock_regions(void) 42 { 43 memset(memblock.memory.regions, 0, 44 memblock.memory.cnt * sizeof(struct memblock_region)); 45 memblock.memory.cnt = 1; 46 memblock.memory.max = INIT_MEMBLOCK_REGIONS; 47 memblock.memory.total_size = 0; 48 49 memset(memblock.reserved.regions, 0, 50 memblock.reserved.cnt * sizeof(struct memblock_region)); 51 memblock.reserved.cnt = 1; 52 memblock.reserved.max = INIT_MEMBLOCK_RESERVED_REGIONS; 53 memblock.reserved.total_size = 0; 54 } 55 56 void reset_memblock_attributes(void) 57 { 58 memblock.memory.name = "memory"; 59 memblock.reserved.name = "reserved"; 60 memblock.bottom_up = false; 61 memblock.current_limit = MEMBLOCK_ALLOC_ANYWHERE; 62 } 63 64 static inline void fill_memblock(void) 65 { 66 memset(memory_block.base, 1, MEM_SIZE); 67 } 68 69 void setup_memblock(void) 70 { 71 reset_memblock_regions(); 72 memblock_add((phys_addr_t)memory_block.base, MEM_SIZE); 73 fill_memblock(); 74 } 75 76 /** 77 * setup_numa_memblock: 78 * Set up a memory layout with multiple NUMA nodes in a previously allocated 79 * dummy physical memory. 80 * @node_fracs: an array representing the fraction of MEM_SIZE contained in 81 * each node in basis point units (one hundredth of 1% or 1/10000). 82 * For example, if node 0 should contain 1/8 of MEM_SIZE, 83 * node_fracs[0] = 1250. 84 * 85 * The nids will be set to 0 through NUMA_NODES - 1. 86 */ 87 void setup_numa_memblock(const unsigned int node_fracs[]) 88 { 89 phys_addr_t base; 90 int flags; 91 92 reset_memblock_regions(); 93 base = (phys_addr_t)memory_block.base; 94 flags = (movable_node_is_enabled()) ? MEMBLOCK_NONE : MEMBLOCK_HOTPLUG; 95 96 for (int i = 0; i < NUMA_NODES; i++) { 97 assert(node_fracs[i] <= BASIS); 98 phys_addr_t size = MEM_SIZE * node_fracs[i] / BASIS; 99 100 memblock_add_node(base, size, i, flags); 101 base += size; 102 } 103 fill_memblock(); 104 } 105 106 void dummy_physical_memory_init(void) 107 { 108 memory_block.base = malloc(MEM_SIZE); 109 assert(memory_block.base); 110 fill_memblock(); 111 } 112 113 void dummy_physical_memory_cleanup(void) 114 { 115 free(memory_block.base); 116 } 117 118 static void usage(const char *prog) 119 { 120 BUILD_BUG_ON(ARRAY_SIZE(help_opts) != ARRAY_SIZE(long_opts) - 1); 121 122 printf("Usage: %s [-%s]\n", prog, short_opts); 123 124 for (int i = 0; long_opts[i].name; i++) { 125 printf(" -%c, --%-12s\t%s\n", long_opts[i].val, 126 long_opts[i].name, help_opts[i]); 127 } 128 129 exit(1); 130 } 131 132 void parse_args(int argc, char **argv) 133 { 134 int c; 135 136 while ((c = getopt_long_only(argc, argv, short_opts, long_opts, 137 NULL)) != -1) { 138 switch (c) { 139 case 'm': 140 movable_node_enabled = true; 141 break; 142 case 'v': 143 verbose = 1; 144 break; 145 default: 146 usage(argv[0]); 147 } 148 } 149 } 150 151 void print_prefixes(const char *postfix) 152 { 153 for (int i = 0; i < nr_prefixes; i++) 154 test_print("%s%s", prefixes[i], DELIM); 155 test_print(postfix); 156 } 157 158 void test_fail(void) 159 { 160 if (verbose) { 161 ksft_test_result_fail(": "); 162 print_prefixes("failed\n"); 163 } 164 } 165 166 void test_pass(void) 167 { 168 if (verbose) { 169 ksft_test_result_pass(": "); 170 print_prefixes("passed\n"); 171 } 172 } 173 174 void test_print(const char *fmt, ...) 175 { 176 if (verbose) { 177 int saved_errno = errno; 178 va_list args; 179 180 va_start(args, fmt); 181 errno = saved_errno; 182 vprintf(fmt, args); 183 va_end(args); 184 } 185 } 186 187 void prefix_reset(void) 188 { 189 memset(prefixes, 0, PREFIXES_MAX * sizeof(char *)); 190 nr_prefixes = 0; 191 } 192 193 void prefix_push(const char *prefix) 194 { 195 assert(nr_prefixes < PREFIXES_MAX); 196 prefixes[nr_prefixes] = prefix; 197 nr_prefixes++; 198 } 199 200 void prefix_pop(void) 201 { 202 if (nr_prefixes > 0) { 203 prefixes[nr_prefixes - 1] = 0; 204 nr_prefixes--; 205 } 206 } 207