1 /*
2  * (c) Copyright 2012 by National Instruments,
3  *        Joe Hershberger <joe.hershberger@ni.com>
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 
10 #include <command.h>
11 #include <environment.h>
12 #include <errno.h>
13 #include <malloc.h>
14 #include <search.h>
15 #include <ubi_uboot.h>
16 #undef crc32
17 
18 char *env_name_spec = "UBI";
19 
20 env_t *env_ptr;
21 
22 DECLARE_GLOBAL_DATA_PTR;
23 
env_init(void)24 int env_init(void)
25 {
26 	/* use default */
27 	gd->env_addr = (ulong)&default_environment[0];
28 	gd->env_valid = 1;
29 
30 	return 0;
31 }
32 
33 #ifdef CONFIG_CMD_SAVEENV
34 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
35 static unsigned char env_flags;
36 
saveenv(void)37 int saveenv(void)
38 {
39 	ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
40 	int ret;
41 
42 	ret = env_export(env_new);
43 	if (ret)
44 		return ret;
45 
46 	if (ubi_part(CONFIG_ENV_UBI_PART, NULL)) {
47 		printf("\n** Cannot find mtd partition \"%s\"\n",
48 		       CONFIG_ENV_UBI_PART);
49 		return 1;
50 	}
51 
52 	env_new->flags = ++env_flags; /* increase the serial */
53 
54 	if (gd->env_valid == 1) {
55 		puts("Writing to redundant UBI... ");
56 		if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME_REDUND,
57 				     (void *)env_new, CONFIG_ENV_SIZE)) {
58 			printf("\n** Unable to write env to %s:%s **\n",
59 			       CONFIG_ENV_UBI_PART,
60 			       CONFIG_ENV_UBI_VOLUME_REDUND);
61 			return 1;
62 		}
63 	} else {
64 		puts("Writing to UBI... ");
65 		if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME,
66 				     (void *)env_new, CONFIG_ENV_SIZE)) {
67 			printf("\n** Unable to write env to %s:%s **\n",
68 			       CONFIG_ENV_UBI_PART,
69 			       CONFIG_ENV_UBI_VOLUME);
70 			return 1;
71 		}
72 	}
73 
74 	puts("done\n");
75 
76 	gd->env_valid = gd->env_valid == 2 ? 1 : 2;
77 
78 	return 0;
79 }
80 #else /* ! CONFIG_SYS_REDUNDAND_ENVIRONMENT */
saveenv(void)81 int saveenv(void)
82 {
83 	ALLOC_CACHE_ALIGN_BUFFER(env_t, env_new, 1);
84 	int ret;
85 
86 	ret = env_export(env_new);
87 	if (ret)
88 		return ret;
89 
90 	if (ubi_part(CONFIG_ENV_UBI_PART, NULL)) {
91 		printf("\n** Cannot find mtd partition \"%s\"\n",
92 		       CONFIG_ENV_UBI_PART);
93 		return 1;
94 	}
95 
96 	if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME, (void *)env_new,
97 			     CONFIG_ENV_SIZE)) {
98 		printf("\n** Unable to write env to %s:%s **\n",
99 		       CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME);
100 		return 1;
101 	}
102 
103 	puts("done\n");
104 	return 0;
105 }
106 #endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */
107 #endif /* CONFIG_CMD_SAVEENV */
108 
109 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
env_relocate_spec(void)110 void env_relocate_spec(void)
111 {
112 	ALLOC_CACHE_ALIGN_BUFFER(char, env1_buf, CONFIG_ENV_SIZE);
113 	ALLOC_CACHE_ALIGN_BUFFER(char, env2_buf, CONFIG_ENV_SIZE);
114 	int crc1_ok = 0, crc2_ok = 0;
115 	env_t *ep, *tmp_env1, *tmp_env2;
116 
117 	tmp_env1 = (env_t *)env1_buf;
118 	tmp_env2 = (env_t *)env2_buf;
119 
120 	if (ubi_part(CONFIG_ENV_UBI_PART, NULL)) {
121 		printf("\n** Cannot find mtd partition \"%s\"\n",
122 		       CONFIG_ENV_UBI_PART);
123 		set_default_env(NULL);
124 		return;
125 	}
126 
127 	if (ubi_volume_read(CONFIG_ENV_UBI_VOLUME, (void *)tmp_env1,
128 			    CONFIG_ENV_SIZE)) {
129 		printf("\n** Unable to read env from %s:%s **\n",
130 		       CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME);
131 	}
132 
133 	if (ubi_volume_read(CONFIG_ENV_UBI_VOLUME_REDUND, (void *)tmp_env2,
134 			    CONFIG_ENV_SIZE)) {
135 		printf("\n** Unable to read redundant env from %s:%s **\n",
136 		       CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME_REDUND);
137 	}
138 
139 	crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) == tmp_env1->crc;
140 	crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) == tmp_env2->crc;
141 
142 	if (!crc1_ok && !crc2_ok) {
143 		set_default_env("!bad CRC");
144 		return;
145 	} else if (crc1_ok && !crc2_ok) {
146 		gd->env_valid = 1;
147 	} else if (!crc1_ok && crc2_ok) {
148 		gd->env_valid = 2;
149 	} else {
150 		/* both ok - check serial */
151 		if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
152 			gd->env_valid = 2;
153 		else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
154 			gd->env_valid = 1;
155 		else if (tmp_env1->flags > tmp_env2->flags)
156 			gd->env_valid = 1;
157 		else if (tmp_env2->flags > tmp_env1->flags)
158 			gd->env_valid = 2;
159 		else /* flags are equal - almost impossible */
160 			gd->env_valid = 1;
161 	}
162 
163 	if (gd->env_valid == 1)
164 		ep = tmp_env1;
165 	else
166 		ep = tmp_env2;
167 
168 	env_flags = ep->flags;
169 	env_import((char *)ep, 0);
170 }
171 #else /* ! CONFIG_SYS_REDUNDAND_ENVIRONMENT */
env_relocate_spec(void)172 void env_relocate_spec(void)
173 {
174 	ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
175 
176 	if (ubi_part(CONFIG_ENV_UBI_PART, NULL)) {
177 		printf("\n** Cannot find mtd partition \"%s\"\n",
178 		       CONFIG_ENV_UBI_PART);
179 		set_default_env(NULL);
180 		return;
181 	}
182 
183 	if (ubi_volume_read(CONFIG_ENV_UBI_VOLUME, (void *)&buf,
184 			    CONFIG_ENV_SIZE)) {
185 		printf("\n** Unable to read env from %s:%s **\n",
186 		       CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME);
187 		set_default_env(NULL);
188 		return;
189 	}
190 
191 	env_import(buf, 1);
192 }
193 #endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */
194