1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2018 Synopsys, Inc. All rights reserved. 4 * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> 5 */ 6 7#include "env-lib.h" 8#include <env.h> 9#include <log.h> 10#include <vsprintf.h> 11#include <linux/errno.h> 12#include <linux/printk.h> 13 14#define MAX_CMD_LEN 25 15 16static void env_clear_common(u32 index, const struct env_map_common *map) 17{ 18 map[index].val->val = 0; 19 map[index].val->set = false; 20} 21 22static int env_read_common(u32 index, const struct env_map_common *map) 23{ 24 u32 val; 25 26 if (!env_get_yesno(map[index].env_name)) { 27 if (map[index].type == ENV_HEX) { 28 val = (u32)env_get_hex(map[index].env_name, 0); 29 debug("ENV: %s: = %#x\n", map[index].env_name, val); 30 } else { 31 val = (u32)env_get_ulong(map[index].env_name, 10, 0); 32 debug("ENV: %s: = %d\n", map[index].env_name, val); 33 } 34 35 map[index].val->val = val; 36 map[index].val->set = true; 37 } 38 39 return 0; 40} 41 42static void env_clear_core(u32 index, const struct env_map_percpu *map) 43{ 44 for (u32 i = 0; i < NR_CPUS; i++) { 45 (*map[index].val)[i].val = 0; 46 (*map[index].val)[i].set = false; 47 } 48} 49 50static int env_read_core(u32 index, const struct env_map_percpu *map) 51{ 52 u32 val; 53 char command[MAX_CMD_LEN]; 54 55 for (u32 i = 0; i < NR_CPUS; i++) { 56 sprintf(command, "%s_%u", map[index].env_name, i); 57 if (!env_get_yesno(command)) { 58 if (map[index].type == ENV_HEX) { 59 val = (u32)env_get_hex(command, 0); 60 debug("ENV: %s: = %#x\n", command, val); 61 } else { 62 val = (u32)env_get_ulong(command, 10, 0); 63 debug("ENV: %s: = %d\n", command, val); 64 } 65 66 (*map[index].val)[i].val = val; 67 (*map[index].val)[i].set = true; 68 } 69 } 70 71 return 0; 72} 73 74static int env_validate_common(u32 index, const struct env_map_common *map) 75{ 76 u32 value = map[index].val->val; 77 bool set = map[index].val->set; 78 u32 min = map[index].min; 79 u32 max = map[index].max; 80 81 /* Check if environment is mandatory */ 82 if (map[index].mandatory && !set) { 83 pr_err("Variable \'%s\' is mandatory, but it is not defined\n", 84 map[index].env_name); 85 86 return -EINVAL; 87 } 88 89 /* Check environment boundary */ 90 if (set && (value < min || value > max)) { 91 if (map[index].type == ENV_HEX) 92 pr_err("Variable \'%s\' must be between %#x and %#x\n", 93 map[index].env_name, min, max); 94 else 95 pr_err("Variable \'%s\' must be between %u and %u\n", 96 map[index].env_name, min, max); 97 98 return -EINVAL; 99 } 100 101 return 0; 102} 103 104static int env_validate_core(u32 index, const struct env_map_percpu *map, 105 bool (*cpu_used)(u32)) 106{ 107 u32 value; 108 bool set; 109 bool mandatory = map[index].mandatory; 110 u32 min, max; 111 112 for (u32 i = 0; i < NR_CPUS; i++) { 113 set = (*map[index].val)[i].set; 114 value = (*map[index].val)[i].val; 115 116 /* Check if environment is mandatory */ 117 if (cpu_used(i) && mandatory && !set) { 118 pr_err("CPU %u is used, but \'%s_%u\' is not defined\n", 119 i, map[index].env_name, i); 120 121 return -EINVAL; 122 } 123 124 min = map[index].min[i]; 125 max = map[index].max[i]; 126 127 /* Check environment boundary */ 128 if (set && (value < min || value > max)) { 129 if (map[index].type == ENV_HEX) 130 pr_err("Variable \'%s_%u\' must be between %#x and %#x\n", 131 map[index].env_name, i, min, max); 132 else 133 pr_err("Variable \'%s_%u\' must be between %d and %d\n", 134 map[index].env_name, i, min, max); 135 136 return -EINVAL; 137 } 138 } 139 140 return 0; 141} 142 143void envs_cleanup_core(const struct env_map_percpu *map) 144{ 145 /* Cleanup env struct first */ 146 for (u32 i = 0; map[i].env_name; i++) 147 env_clear_core(i, map); 148} 149 150void envs_cleanup_common(const struct env_map_common *map) 151{ 152 /* Cleanup env struct first */ 153 for (u32 i = 0; map[i].env_name; i++) 154 env_clear_common(i, map); 155} 156 157int envs_read_common(const struct env_map_common *map) 158{ 159 int ret; 160 161 for (u32 i = 0; map[i].env_name; i++) { 162 ret = env_read_common(i, map); 163 if (ret) 164 return ret; 165 } 166 167 return 0; 168} 169 170int envs_validate_common(const struct env_map_common *map) 171{ 172 int ret; 173 174 for (u32 i = 0; map[i].env_name; i++) { 175 ret = env_validate_common(i, map); 176 if (ret) 177 return ret; 178 } 179 180 return 0; 181} 182 183int envs_read_validate_common(const struct env_map_common *map) 184{ 185 int ret; 186 187 envs_cleanup_common(map); 188 189 ret = envs_read_common(map); 190 if (ret) 191 return ret; 192 193 ret = envs_validate_common(map); 194 if (ret) 195 return ret; 196 197 return 0; 198} 199 200int envs_read_validate_core(const struct env_map_percpu *map, 201 bool (*cpu_used)(u32)) 202{ 203 int ret; 204 205 envs_cleanup_core(map); 206 207 for (u32 i = 0; map[i].env_name; i++) { 208 ret = env_read_core(i, map); 209 if (ret) 210 return ret; 211 } 212 213 for (u32 i = 0; map[i].env_name; i++) { 214 ret = env_validate_core(i, map, cpu_used); 215 if (ret) 216 return ret; 217 } 218 219 return 0; 220} 221 222int envs_process_and_validate(const struct env_map_common *common, 223 const struct env_map_percpu *core, 224 bool (*cpu_used)(u32)) 225{ 226 int ret; 227 228 ret = envs_read_validate_common(common); 229 if (ret) 230 return ret; 231 232 ret = envs_read_validate_core(core, cpu_used); 233 if (ret) 234 return ret; 235 236 return 0; 237} 238 239static int args_envs_read_search(const struct env_map_common *map, 240 int argc, char *const argv[]) 241{ 242 for (int i = 0; map[i].env_name; i++) { 243 if (!strcmp(argv[0], map[i].env_name)) 244 return i; 245 } 246 247 pr_err("Unexpected argument '%s', can't parse\n", argv[0]); 248 249 return -ENOENT; 250} 251 252static int arg_read_set(const struct env_map_common *map, u32 i, int argc, 253 char *const argv[]) 254{ 255 char *endp = argv[1]; 256 257 if (map[i].type == ENV_HEX) 258 map[i].val->val = hextoul(argv[1], &endp); 259 else 260 map[i].val->val = dectoul(argv[1], &endp); 261 262 map[i].val->set = true; 263 264 if (*endp == '\0') 265 return 0; 266 267 pr_err("Unexpected argument '%s', can't parse\n", argv[1]); 268 269 map[i].val->set = false; 270 271 return -EINVAL; 272} 273 274int args_envs_enumerate(const struct env_map_common *map, int enum_by, 275 int argc, char *const argv[]) 276{ 277 u32 i; 278 279 if (argc % enum_by) { 280 pr_err("unexpected argument number: %d\n", argc); 281 return -EINVAL; 282 } 283 284 while (argc > 0) { 285 i = args_envs_read_search(map, argc, argv); 286 if (i < 0) 287 return i; 288 289 debug("ARG: found '%s' with index %d\n", map[i].env_name, i); 290 291 if (i < 0) { 292 pr_err("unknown arg: %s\n", argv[0]); 293 return -EINVAL; 294 } 295 296 if (arg_read_set(map, i, argc, argv)) 297 return -EINVAL; 298 299 debug("ARG: value.s '%s' == %#x\n", argv[1], map[i].val->val); 300 301 argc -= enum_by; 302 argv += enum_by; 303 } 304 305 return 0; 306} 307