xref: /rk3399_rockchip-uboot/env/envf.c (revision cbfcaedb2b42d90f95783eb836cee6cbd224719e)
1 /*
2  * Copyright (c) 2022 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <boot_rkimg.h>
9 #include <environment.h>
10 #include <memalign.h>
11 #include <part.h>
12 
13 DECLARE_GLOBAL_DATA_PTR;
14 
15 /*
16  * Example: ./tools/mkenvimage -s 0x8000 -p 0x0 -o env.img env.txt
17  */
18 #define ENVF_MSG(fmt, args...)	printf("ENVF: "fmt, ##args)
19 #define ENVF_DBG(fmt, args...)	debug("ENVF: "fmt, ##args)
20 
21 #define EMSG_ARGS		"error: please use \"sys_bootargs\" but not \"bootargs\""
22 #define BLK_CNT(desc, sz)	((sz) / (desc)->blksz)
23 #define ENVF_MAX		64
24 
25 static ulong env_size, env_offset, env_offset_redund;
26 static const char *part_type[] = { "mtdparts", "blkdevparts", };
27 
28 /*
29  * In case of env and env-backup partitions are too large that exceeds the limit
30  * of CONFIG_SPL_SYS_MALLOC_F_LEN. we prefer to use a static address as an env
31  * buffer. The tail of bss section is good choice from experience.
32  */
33 #ifdef CONFIG_SPL_BUILD
34 static void *spl_env =
35 	(void *)CONFIG_SPL_BSS_START_ADDR + CONFIG_SPL_BSS_MAX_SIZE;
36 #else
37 static u32 envf_num;
38 static const char *envf_list[ENVF_MAX];
39 #endif
40 
41 static const char *env_get_string(env_t *env, u32 size, const char *str)
42 {
43 	const char *dp;
44 	u32 env_size;
45 
46 	dp = (const char *)env->data;
47 	env_size = size - ENV_HEADER_SIZE;
48 	do {
49 		/* skip leading white space */
50 		while (*dp == ' ' || *dp == '\t')
51 			++dp;
52 
53 		debug("ENTRY: %s\n", dp);
54 		if (strstr(dp, str)) {
55 			debug("FIND: %s\n", dp);
56 			return dp;
57 		}
58 
59 		/* point to next ENTRY */
60 		dp += strlen(dp) + 1;
61 	} while (((ulong)dp < (ulong)env->data + env_size) && *dp);
62 
63 	debug("NOT-FIND: %s\n", str);
64 
65 	return NULL;
66 }
67 
68 static void envf_init_location(struct blk_desc *desc)
69 {
70 	/* eMMC (default) */
71 	env_size = CONFIG_ENV_SIZE;
72 	env_offset = CONFIG_ENV_OFFSET;
73 	env_offset_redund = CONFIG_ENV_OFFSET_REDUND;
74 
75 #if defined(CONFIG_MTD_SPI_NAND) || defined(CONFIG_CMD_NAND)
76 	/* nand or spi-nand */
77 	if (desc->if_type == IF_TYPE_MTD &&
78 	    (desc->devnum == BLK_MTD_SPI_NAND || desc->devnum == BLK_MTD_NAND)) {
79 		env_size = CONFIG_ENV_NAND_SIZE;
80 		env_offset = CONFIG_ENV_NAND_OFFSET;
81 		env_offset_redund = CONFIG_ENV_NAND_OFFSET_REDUND;
82 	}
83 #endif
84 #if defined(CONFIG_SPI_FLASH)
85 	/* spi-nor */
86 	if (desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NOR) {
87 		env_size = CONFIG_ENV_NOR_SIZE;
88 		env_offset = CONFIG_ENV_NOR_OFFSET;
89 		env_offset_redund = CONFIG_ENV_NOR_OFFSET_REDUND;
90 	}
91 #endif
92 	if (env_offset == env_offset_redund)
93 		env_offset_redund = 0;
94 }
95 
96 static int env_read(struct blk_desc *desc, u32 offset, u32 size, env_t **envp)
97 {
98 	lbaint_t data_size;
99 	lbaint_t blk_off;
100 	lbaint_t blk_cnt;
101 	env_t *env;
102 	int ret;
103 
104 #ifdef CONFIG_SPL_BUILD
105 	env = spl_env;
106 #else
107 	env = malloc(size);
108 	if (!env)
109 		return -ENOMEM;
110 #endif
111 	data_size = size - ENV_HEADER_SIZE;
112 	blk_off = BLK_CNT(desc, offset);
113 	blk_cnt = BLK_CNT(desc, size);
114 
115 	if (blk_dread(desc, blk_off, blk_cnt, (void *)env) != blk_cnt) {
116 		ret = -EIO;
117 		goto fail;
118 	}
119 
120 	if (crc32(0, env->data, data_size) != env->crc) {
121 		ENVF_MSG("!bad CRC @ 0x%x\n", offset);
122 		ret = -EINVAL;
123 		goto fail;
124 	}
125 
126 	*envp = env;
127 
128 	return 0;
129 fail:
130 #ifndef CONFIG_SPL_BUILD
131 	free(env);
132 #endif
133 	return ret;
134 }
135 
136 static env_t *envf_read(struct blk_desc *desc)
137 {
138 	env_t *env = NULL;
139 	int ret;
140 
141 	if (!desc)
142 		return NULL;
143 
144 	envf_init_location(desc);
145 
146 	ret = env_read(desc, env_offset, env_size, &env);
147 	if (ret < 0 && env_offset_redund)
148 		ret = env_read(desc, env_offset_redund, env_size, &env);
149 
150 	return env;
151 }
152 
153 char *envf_get_part_table(struct blk_desc *desc)
154 {
155 	const char *list = NULL;
156 	env_t *env;
157 
158 	if (!desc)
159 		goto out;
160 
161 	env = envf_read(desc);
162 	if (!env)
163 		goto out;
164 
165 	ENVF_MSG("Primary 0x%08lx - 0x%08lx\n", env_offset, env_offset + env_size);
166 	if (env_offset_redund)
167 		ENVF_MSG("Backup  0x%08lx - 0x%08lx\n",
168 			 env_offset_redund, env_offset_redund + env_size);
169 
170 	list = env_get_string(env, env_size, part_type[0]);
171 	if (!list)
172 		list = env_get_string(env, env_size, part_type[1]);
173 	if (!list)
174 		ENVF_MSG("Unavailable env part table\n");
175 	else
176 		ENVF_MSG("OK\n");
177 out:
178 	return (char *)list;
179 }
180 
181 #ifndef CONFIG_SPL_BUILD
182 static int envf_init_vars(void)
183 {
184 	char *tok, *p;
185 
186 	tok = strdup(CONFIG_ENVF_LIST);
187 	if (!tok)
188 		return 0;
189 
190 	envf_num = 0;
191 	p = strtok(tok, " ");
192 	while (p && envf_num < ENVF_MAX) {
193 		if (!strcmp(p, "bootargs")) {
194 			printf("%s\n", EMSG_ARGS);
195 			run_command("download", 0);
196 		}
197 		envf_list[envf_num++] = p;
198 		p = strtok(NULL, " ");
199 	}
200 
201 	return envf_num;
202 }
203 
204 static int envf_add_bootargs(void)
205 {
206 	char *part_list;
207 	char *bootargs;
208 	int i;
209 
210 	for (i = 0; i < ARRAY_SIZE(part_type); i++) {
211 		part_list = env_get(part_type[i]);
212 		if (part_list)
213 			break;
214 	}
215 	if (!part_list)
216 		return -EINVAL;
217 
218 	bootargs = calloc(1, strlen(part_list) + strlen(part_type[i]) + 2);
219 	if (!bootargs)
220 		return -ENOMEM;
221 
222 	strcat(bootargs, part_type[i]);
223 	strcat(bootargs, "=");
224 	strcat(bootargs, part_list);
225 	env_update("bootargs", bootargs);
226 	free(bootargs);
227 
228 	return 0;
229 }
230 
231 static int envf_load(void)
232 {
233 	struct blk_desc *desc;
234 	env_t *env;
235 
236 	desc = rockchip_get_bootdev();
237 	if (!desc) {
238 		printf("dev desc null!\n");
239 		return 0;
240 	}
241 
242 	env = envf_read(desc);
243 	if (!env)
244 		return -EINVAL;
245 
246 	if (envf_init_vars() > 0) {
247 		if (!himport_r(&env_htab, (char *)env->data, env_size, '\0',
248 			H_NOCLEAR, 0, envf_num, (char * const *)envf_list)) {
249 			ENVF_MSG("envf himport error: %d\n", errno);
250 			return -EINTR;
251 		}
252 	}
253 
254 	envf_add_bootargs();
255 
256 	return 0;
257 }
258 
259 static int envf_save(void)
260 {
261 	ALLOC_CACHE_ALIGN_BUFFER(env_t, env, 1);
262 	struct blk_desc *desc;
263 	ssize_t	len;
264 	u32 blk_cnt;
265 	char *res;
266 	int ret = 0;
267 
268 	desc = rockchip_get_bootdev();
269 	if (!desc) {
270 		printf("dev desc null!\n");
271 		return -EINVAL;
272 	}
273 
274 	res = (char *)env->data;
275 	len = hexport_r(&env_htab, '\0', H_MATCH_KEY | H_MATCH_IDENT,
276 			&res, env_size - ENV_HEADER_SIZE,
277 			envf_num, (char * const *)envf_list);
278 	if (len < 0) {
279 		ENVF_MSG("hexpor error: %d\n", errno);
280 		return -EINVAL;
281 	}
282 
283 	env->crc = crc32(0, env->data, env_size - ENV_HEADER_SIZE);
284 	blk_cnt = BLK_CNT(desc, env_size);
285 	if (blk_dwrite(desc, BLK_CNT(desc, env_offset),
286 		       blk_cnt, (char *)env) != blk_cnt) {
287 		ret = -EIO;
288 		ENVF_MSG("io error\n");
289 	}
290 
291 	if (env_offset_redund) {
292 		if (blk_dwrite(desc, BLK_CNT(desc, env_offset_redund),
293 			       blk_cnt, (char *)env) != blk_cnt)
294 			ENVF_MSG("redundant: io error\n");
295 		else
296 			ret = 0;
297 	}
298 
299 	return ret;
300 }
301 
302 static int envf_nowhere_init(void)
303 {
304 	gd->env_addr	= (ulong)&default_environment[0];
305 	gd->env_valid	= ENV_INVALID;
306 
307 	return 0;
308 }
309 
310 U_BOOT_ENV_LOCATION(nowhere) = {
311 	.location	= ENVL_NOWHERE,
312 	.init		= envf_nowhere_init,
313 	.load		= envf_load,
314 	.save		= env_save_ptr(envf_save),
315 	ENV_NAME("envf")
316 };
317 #endif
318 
319