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