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