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