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