mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-30 15:03:18 +00:00
1e94b46f73
This old patch was marked as deferred. Bring it back to life, to continue towards the removal of common.h Move this out of the common header and include it only where needed. Signed-off-by: Simon Glass <sjg@chromium.org>
304 lines
6.1 KiB
C
304 lines
6.1 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (C) 2018 Synopsys, Inc. All rights reserved.
|
|
* Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
|
|
*/
|
|
|
|
#include "env-lib.h"
|
|
#include <env.h>
|
|
#include <log.h>
|
|
#include <linux/printk.h>
|
|
|
|
#define MAX_CMD_LEN 25
|
|
|
|
static void env_clear_common(u32 index, const struct env_map_common *map)
|
|
{
|
|
map[index].val->val = 0;
|
|
map[index].val->set = false;
|
|
}
|
|
|
|
static int env_read_common(u32 index, const struct env_map_common *map)
|
|
{
|
|
u32 val;
|
|
|
|
if (!env_get_yesno(map[index].env_name)) {
|
|
if (map[index].type == ENV_HEX) {
|
|
val = (u32)env_get_hex(map[index].env_name, 0);
|
|
debug("ENV: %s: = %#x\n", map[index].env_name, val);
|
|
} else {
|
|
val = (u32)env_get_ulong(map[index].env_name, 10, 0);
|
|
debug("ENV: %s: = %d\n", map[index].env_name, val);
|
|
}
|
|
|
|
map[index].val->val = val;
|
|
map[index].val->set = true;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void env_clear_core(u32 index, const struct env_map_percpu *map)
|
|
{
|
|
for (u32 i = 0; i < NR_CPUS; i++) {
|
|
(*map[index].val)[i].val = 0;
|
|
(*map[index].val)[i].set = false;
|
|
}
|
|
}
|
|
|
|
static int env_read_core(u32 index, const struct env_map_percpu *map)
|
|
{
|
|
u32 val;
|
|
char command[MAX_CMD_LEN];
|
|
|
|
for (u32 i = 0; i < NR_CPUS; i++) {
|
|
sprintf(command, "%s_%u", map[index].env_name, i);
|
|
if (!env_get_yesno(command)) {
|
|
if (map[index].type == ENV_HEX) {
|
|
val = (u32)env_get_hex(command, 0);
|
|
debug("ENV: %s: = %#x\n", command, val);
|
|
} else {
|
|
val = (u32)env_get_ulong(command, 10, 0);
|
|
debug("ENV: %s: = %d\n", command, val);
|
|
}
|
|
|
|
(*map[index].val)[i].val = val;
|
|
(*map[index].val)[i].set = true;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int env_validate_common(u32 index, const struct env_map_common *map)
|
|
{
|
|
u32 value = map[index].val->val;
|
|
bool set = map[index].val->set;
|
|
u32 min = map[index].min;
|
|
u32 max = map[index].max;
|
|
|
|
/* Check if environment is mandatory */
|
|
if (map[index].mandatory && !set) {
|
|
pr_err("Variable \'%s\' is mandatory, but it is not defined\n",
|
|
map[index].env_name);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Check environment boundary */
|
|
if (set && (value < min || value > max)) {
|
|
if (map[index].type == ENV_HEX)
|
|
pr_err("Variable \'%s\' must be between %#x and %#x\n",
|
|
map[index].env_name, min, max);
|
|
else
|
|
pr_err("Variable \'%s\' must be between %u and %u\n",
|
|
map[index].env_name, min, max);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int env_validate_core(u32 index, const struct env_map_percpu *map,
|
|
bool (*cpu_used)(u32))
|
|
{
|
|
u32 value;
|
|
bool set;
|
|
bool mandatory = map[index].mandatory;
|
|
u32 min, max;
|
|
|
|
for (u32 i = 0; i < NR_CPUS; i++) {
|
|
set = (*map[index].val)[i].set;
|
|
value = (*map[index].val)[i].val;
|
|
|
|
/* Check if environment is mandatory */
|
|
if (cpu_used(i) && mandatory && !set) {
|
|
pr_err("CPU %u is used, but \'%s_%u\' is not defined\n",
|
|
i, map[index].env_name, i);
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
min = map[index].min[i];
|
|
max = map[index].max[i];
|
|
|
|
/* Check environment boundary */
|
|
if (set && (value < min || value > max)) {
|
|
if (map[index].type == ENV_HEX)
|
|
pr_err("Variable \'%s_%u\' must be between %#x and %#x\n",
|
|
map[index].env_name, i, min, max);
|
|
else
|
|
pr_err("Variable \'%s_%u\' must be between %d and %d\n",
|
|
map[index].env_name, i, min, max);
|
|
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void envs_cleanup_core(const struct env_map_percpu *map)
|
|
{
|
|
/* Cleanup env struct first */
|
|
for (u32 i = 0; map[i].env_name; i++)
|
|
env_clear_core(i, map);
|
|
}
|
|
|
|
void envs_cleanup_common(const struct env_map_common *map)
|
|
{
|
|
/* Cleanup env struct first */
|
|
for (u32 i = 0; map[i].env_name; i++)
|
|
env_clear_common(i, map);
|
|
}
|
|
|
|
int envs_read_common(const struct env_map_common *map)
|
|
{
|
|
int ret;
|
|
|
|
for (u32 i = 0; map[i].env_name; i++) {
|
|
ret = env_read_common(i, map);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int envs_validate_common(const struct env_map_common *map)
|
|
{
|
|
int ret;
|
|
|
|
for (u32 i = 0; map[i].env_name; i++) {
|
|
ret = env_validate_common(i, map);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int envs_read_validate_common(const struct env_map_common *map)
|
|
{
|
|
int ret;
|
|
|
|
envs_cleanup_common(map);
|
|
|
|
ret = envs_read_common(map);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = envs_validate_common(map);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int envs_read_validate_core(const struct env_map_percpu *map,
|
|
bool (*cpu_used)(u32))
|
|
{
|
|
int ret;
|
|
|
|
envs_cleanup_core(map);
|
|
|
|
for (u32 i = 0; map[i].env_name; i++) {
|
|
ret = env_read_core(i, map);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
for (u32 i = 0; map[i].env_name; i++) {
|
|
ret = env_validate_core(i, map, cpu_used);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int envs_process_and_validate(const struct env_map_common *common,
|
|
const struct env_map_percpu *core,
|
|
bool (*cpu_used)(u32))
|
|
{
|
|
int ret;
|
|
|
|
ret = envs_read_validate_common(common);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = envs_read_validate_core(core, cpu_used);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int args_envs_read_search(const struct env_map_common *map,
|
|
int argc, char *const argv[])
|
|
{
|
|
for (int i = 0; map[i].env_name; i++) {
|
|
if (!strcmp(argv[0], map[i].env_name))
|
|
return i;
|
|
}
|
|
|
|
pr_err("Unexpected argument '%s', can't parse\n", argv[0]);
|
|
|
|
return -ENOENT;
|
|
}
|
|
|
|
static int arg_read_set(const struct env_map_common *map, u32 i, int argc,
|
|
char *const argv[])
|
|
{
|
|
char *endp = argv[1];
|
|
|
|
if (map[i].type == ENV_HEX)
|
|
map[i].val->val = hextoul(argv[1], &endp);
|
|
else
|
|
map[i].val->val = dectoul(argv[1], &endp);
|
|
|
|
map[i].val->set = true;
|
|
|
|
if (*endp == '\0')
|
|
return 0;
|
|
|
|
pr_err("Unexpected argument '%s', can't parse\n", argv[1]);
|
|
|
|
map[i].val->set = false;
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
int args_envs_enumerate(const struct env_map_common *map, int enum_by,
|
|
int argc, char *const argv[])
|
|
{
|
|
u32 i;
|
|
|
|
if (argc % enum_by) {
|
|
pr_err("unexpected argument number: %d\n", argc);
|
|
return -EINVAL;
|
|
}
|
|
|
|
while (argc > 0) {
|
|
i = args_envs_read_search(map, argc, argv);
|
|
if (i < 0)
|
|
return i;
|
|
|
|
debug("ARG: found '%s' with index %d\n", map[i].env_name, i);
|
|
|
|
if (i < 0) {
|
|
pr_err("unknown arg: %s\n", argv[0]);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (arg_read_set(map, i, argc, argv))
|
|
return -EINVAL;
|
|
|
|
debug("ARG: value.s '%s' == %#x\n", argv[1], map[i].val->val);
|
|
|
|
argc -= enum_by;
|
|
argv += enum_by;
|
|
}
|
|
|
|
return 0;
|
|
}
|