blob: 1256bca5aed3cf1dbf3b69f43687d3fd38cecde9 [file] [log] [blame]
Bo Lv72d0e902023-01-02 14:27:34 +00001// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2/*
3 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
4 */
5
6#include <config.h>
7#include <common.h>
8#include <command.h>
9#include <env.h>
Sam Wu6f3d40e2023-04-22 01:10:27 +080010#include <env_internal.h>
Bo Lv72d0e902023-01-02 14:27:34 +000011#include <cli.h>
12#include <errno.h>
13#include <malloc.h>
14#include <linux/stddef.h>
Sam Wu6f3d40e2023-04-22 01:10:27 +080015#include <linux/crc32.h>
Bo Lv72d0e902023-01-02 14:27:34 +000016#include <asm/byteorder.h>
Sam Wu6f3d40e2023-04-22 01:10:27 +080017#include <amlogic/store_wrapper.h>
Bo Lv72d0e902023-01-02 14:27:34 +000018
19static const char* const temp_for_compile[] = {"__test1","__test2","__test3",NULL};
20extern const char * const _env_args_reserve_[0] __attribute__((weak, alias("temp_for_compile")));
21
22#define debugP(fmt...) //printf("dbg[ENV]" fmt)
23#define errorP(fmt...) do {printf("ERR[ENV]L%d:", __LINE__); printf(fmt); } while (0)
24#define wrnP(fmt...) printf("WRN[ENV]" fmt)
25#define MsgP(fmt...) printf("MSG[ENV]" fmt)
26
27static int _reserve_env_list_after_defenv(const int reservNum, const char* const reservNameList[])
28{
29 int ret = 0;
30 int index = 0;
31 unsigned sumOfEnvVal = 0;//sum of strlen(getenv(env_i))
32 const int MaxReservNum = CONFIG_SYS_MAXARGS - 1;
33 const char* valListBuf[MaxReservNum];//store at most 64 envs
34 char* tmpEnvBuf = NULL;
35
36 if (reservNum > MaxReservNum) {
37 errorP("max reserved env list num %d < wanted %d\n", MaxReservNum, reservNum);
38 return __LINE__;
39 }
40 //1, cal the total buf size needed to save the envs
41 for (index = 0; index < reservNum; ++index)
42 {
43 const char* cfgEnvKey = reservNameList[index];
44 const char* cfgEnvVal = env_get(cfgEnvKey);
45
46 if (cfgEnvVal) {
47 sumOfEnvVal += strlen(cfgEnvVal) + 1;
48 }
49 valListBuf[index] = cfgEnvVal;
50 }
51
52 //2, transfer the env values to buffer
53 if (sumOfEnvVal)
54 {
55 tmpEnvBuf = (char*)malloc(sumOfEnvVal);
56 if (!tmpEnvBuf) {
57 errorP("Fail in malloc(%d)\n", sumOfEnvVal);
58 return __LINE__;
59 }
60 memset(tmpEnvBuf, 0, sumOfEnvVal);
61
62 char* tmpbuf = tmpEnvBuf;
63 for (index = 0; index < reservNum; ++index )
64 {
65 const char* valBeforeDef = valListBuf[index];
66
67 if (!valBeforeDef) continue;
68
69 const unsigned thisValLen = strlen(valBeforeDef) + 1;
70 memcpy(tmpbuf, valBeforeDef, thisValLen);
71 valListBuf[index] = tmpbuf;
72 tmpbuf += thisValLen ;
73 debugP("tmpEnvBuf=%p, tmpbuf=%p, thisValLen=%d\n", tmpEnvBuf, tmpbuf, thisValLen);
74 debugP("cp:k[%s]%s-->%s\n", reservNameList[index], valBeforeDef, tmpEnvBuf);
75 }
76 }
77
78 env_set_default("## defenv_reserve ##", 0);
79
80 if (sumOfEnvVal)
81 {
82 for (index = 0; index < reservNum; ++index)
83 {
84 const char* cfgEnvKey = reservNameList[index];
85 const char* valAftDef = valListBuf[index];
86
87 if (valAftDef)
88 {
89 env_set(cfgEnvKey, valAftDef);
90 debugP("set[%s=%s]\n", cfgEnvKey, valAftDef);
91 }
92 }
93 }
94
95 if (tmpEnvBuf) free(tmpEnvBuf) ;
96 return ret;
97}
98
99static int do_defenv_reserv(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
100{
101 int envListNum = argc - 1;
102 const char** envListArr = (const char**)(argv + 1);
103
104 if (!envListNum)
105 {
106 envListArr = (const char**)_env_args_reserve_;
107
108 const char** pArr = (const char**)envListArr;
109 while (*pArr++) ++envListNum;
110 }
111
112 int ret = _reserve_env_list_after_defenv(envListNum, envListArr);
113
114 return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS;
115}
116
117U_BOOT_CMD_COMPLETE(
118 defenv_reserve, //command name
119 CONFIG_SYS_MAXARGS, //maxargs
120 0, //repeatable
121 do_defenv_reserv, //command function
122 "reserve some specified envs after defaulting env", //description
123 " argv: defenv_reserve <reserv_en0 reserv_env1 ...> \n" //usage
124 " - e.g. \n"
125 " defenv_reserve :\n" //usage
126 " NOT env list , reserv cfg array '_env_args_reserve_' in gxbb_p200.c\n"
127 " defenv_reserve reserv_en0, reserv_env1, ...\n" //usage
128 " reserve specified envs after defaulting env\n", //usage
129 var_complete
130);
131
132/*
Sam Wu6f3d40e2023-04-22 01:10:27 +0800133 * update_env_part, update env in flash
134 * usage: update_env_part <options -f/-s/-p> env1 env2 env3 ...
135 * Just add/update/delete env in flash, not replace all env like saveenv
136 * updaete include any of add/update/delete
137 * Reasons to replace saveenv with update_env_part
138 * >>Usually only save env u need, not include others like bootdelay
139 * >>Most cases, we need update env iff changed, and need speed up as save env to flash cost time
140 * todo: check not arg duplicated in argv
Bo Lv72d0e902023-01-02 14:27:34 +0000141 */
142#if CONFIG_IS_ENABLED(AML_UPDATE_ENV)
143static int do_update_env_part(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
144{
145 int i = 0;
146 int ret = CMD_RET_SUCCESS;
147 int silent = 0;//don't tell empty env, 0 will print which env isnot exist
148 int force = 0;//when 1, even no all env list exist will update env part
149 int print = 0;//print env name/value after update env part
Sam Wu6f3d40e2023-04-22 01:10:27 +0800150 const int BUF_SZ = CONFIG_ENV_SIZE * 2;
Bo Lv72d0e902023-01-02 14:27:34 +0000151 char *env_part_buf = NULL;
Sam Wu6f3d40e2023-04-22 01:10:27 +0800152 char *new_env_buf = NULL;
153 env_t *ep = NULL;
154 unsigned char *pdata = NULL;
155 uint32_t crc;
156 uint32_t n_env_in_flash = 0;//0 if all env not in flash, argc -1 if all env in flash
157 int need_update_env = 0;
158 const char *env_end = NULL;//current last kv's \0
159 unsigned long env_len = 0;
160 unsigned int save_buf = 0;//1 if need save new_env_buf
Bo Lv72d0e902023-01-02 14:27:34 +0000161
162 if (argc < 2) {
163 MsgP("Need at least one env specify to update\n");
164 return CMD_RET_USAGE;
165 }
166 while (argc > 1 && **(argv + 1) == '-') {
167 char *arg = *++argv;
168
169 --argc;
170 while (*++arg) {
171 switch (*arg) {
172 case 'p':/* print */
173 print = true;
174 break;
175 case 's':/* silent */
176 silent = true;
177 break;
178 case 'f':/* force */
179 force = true;
180 break;
181 default:
182 return CMD_RET_USAGE;
183 }
184 }
185 }
186 for (i = 1; i < argc; ++i) {
187 if (env_get(argv[i])) {
Bo Lv72d0e902023-01-02 14:27:34 +0000188 continue;
189 }
Sam Wu6f3d40e2023-04-22 01:10:27 +0800190 if (!force) {//force mode allow update env part even some env not exist
191 MsgP("env %s NOT exist and not -f, so cannot update flash env\n", argv[i]);
Bo Lv72d0e902023-01-02 14:27:34 +0000192 return CMD_RET_FAILURE;
193 }
194 }
Bo Lv72d0e902023-01-02 14:27:34 +0000195 env_part_buf = malloc(BUF_SZ);
196 if (!env_part_buf) {
197 errorP("Fail malloc buf sz 0x%x\n", BUF_SZ);
198 return CMD_RET_FAILURE;
199 }
Sam Wu6f3d40e2023-04-22 01:10:27 +0800200 new_env_buf = env_part_buf + CONFIG_ENV_SIZE;
Bo Lv72d0e902023-01-02 14:27:34 +0000201
Sam Wu6f3d40e2023-04-22 01:10:27 +0800202 //#1> record env list need to update
203 debugP("argc %d, argv[1] %s\n", argc, argv[1]);
204 env_set("_update_env_list", NULL);
205 for (i = 1; i < argc; ++i) {
Bo Lv72d0e902023-01-02 14:27:34 +0000206 env_set("_temp_env_", argv[i]);
Sam Wu6f3d40e2023-04-22 01:10:27 +0800207 run_command("env set _update_env_list ${_update_env_list} ${_temp_env_}", 0);
Bo Lv72d0e902023-01-02 14:27:34 +0000208 }
Sam Wu6f3d40e2023-04-22 01:10:27 +0800209 env_set("_temp_env_", NULL);
210 if (!silent) //print env list which updated in part env if not same
Bo Lv72d0e902023-01-02 14:27:34 +0000211 MsgP("_update_env_list: %s\n", env_get("_update_env_list"));
Sam Wu6f3d40e2023-04-22 01:10:27 +0800212
213 //#2> read env and check if valid
214 if (store_get_type() == BOOT_NONE) {
215 errorP("env_storage: must init before load\n");
Bo Lv72d0e902023-01-02 14:27:34 +0000216 ret = CMD_RET_FAILURE; goto _update_env_part_err;
217 }
Sam Wu6f3d40e2023-04-22 01:10:27 +0800218 if (store_rsv_read(RSV_ENV, BUF_SZ, env_part_buf)) {
219 errorP("fail read env from storage\n");
Bo Lv72d0e902023-01-02 14:27:34 +0000220 ret = CMD_RET_FAILURE; goto _update_env_part_err;
Sam Wu6f3d40e2023-04-22 01:10:27 +0800221 } else {
222 ep = (env_t *)env_part_buf;
223 pdata = ep->data;
224 memcpy(&crc, &ep->crc, sizeof(crc));
225 if (crc32(0, pdata, ENV_SIZE) != crc) {
226 errorP("bad CRC in storage, so directly save all env to storage\n");
227 ret = env_save();
228 goto _update_env_part_err;
229 }
Bo Lv72d0e902023-01-02 14:27:34 +0000230 }
Bo Lv72d0e902023-01-02 14:27:34 +0000231
Sam Wu6f3d40e2023-04-22 01:10:27 +0800232 //#3> parse storage env and check if need update, most cases true
233 //compare if all env vars are same in flash
234 //case 1: usr env and store env both exist, but value not same (include usr env val empty)
235 //case 2: usr env not exist on store, but usr env val not empty
236 if (!pdata) {
237 errorP("err pdata\n");
238 ret = CMD_RET_FAILURE; goto _update_env_part_err;
239 } else {
240 const char *current_kv = (char *)pdata;//env1=val\0
241 unsigned int n_same_env = 0;
242 const char *kvsep = "=";
Bo Lv72d0e902023-01-02 14:27:34 +0000243
Sam Wu6f3d40e2023-04-22 01:10:27 +0800244 //3.1>get the true end postion
245 for (env_end = (char *)pdata; env_end < (char *)pdata + ENV_SIZE;) {
246 const char *p =
247 env_end + strnlen(env_end, (char *)pdata + ENV_SIZE - env_end);
Bo Lv72d0e902023-01-02 14:27:34 +0000248
Sam Wu6f3d40e2023-04-22 01:10:27 +0800249 if (*p != '\0') {
250 errorP("env need end with 0 but %c\n", *p);
251 ret = CMD_RET_FAILURE; goto _update_env_part_err;
252 }
253 if (++p - (char *)pdata >= ENV_SIZE) {
254 env_end = --p;
Bo Lv72d0e902023-01-02 14:27:34 +0000255 break;
256 }
Sam Wu6f3d40e2023-04-22 01:10:27 +0800257 if (*p == '\0') {
258 env_end = --p;
259 break;
260 }
261 env_end = p;
262 }
263 env_len = env_end - (char *)pdata;
264 if (*env_end || env_len < 1024) {
265 errorP("too short env or env end %c err\n", *env_end);
266 ret = CMD_RET_FAILURE; goto _update_env_part_err;
267 }
268 debugP("part env addr 0x%p, end 0x%p, sz %lx\n",
269 env_part_buf, env_end, env_end - env_part_buf);
Bo Lv72d0e902023-01-02 14:27:34 +0000270
Sam Wu6f3d40e2023-04-22 01:10:27 +0800271 //3.2> check if NOT need update flash, which is most used case
272 for (; current_kv < env_end; current_kv += strlen(current_kv) + 1) {
273 const char *s_env_v = strpbrk(current_kv, kvsep);//storage env value
274
275 if (!s_env_v) {
276 errorP("err env in storage, not k=v fmt\n%s\n", current_kv);
277 ret = CMD_RET_FAILURE; goto _update_env_part_err;
278 }
279 ++s_env_v;//skip '='
280 //case 1, usr val == storage env val, skip
281 //case 2, usr val empty, del it if exist in storage
282 //case 2, usr val not empty, del it if exist in storage, append new to end
283 for (i = 1; i < argc; ++i) {
284 const char *usr_env = argv[i];
285 const char *usr_env_val = env_get(usr_env);
286
287 if (strncmp(current_kv, usr_env, s_env_v - current_kv - 1))
288 continue;
289 //Found key
290 ++n_env_in_flash;
291 if (!usr_env_val) {//need delete env in flash
292 MsgP("store env %s need remove\n", usr_env);
Bo Lv72d0e902023-01-02 14:27:34 +0000293 need_update_env = 1;
294 break;
295 }
Sam Wu6f3d40e2023-04-22 01:10:27 +0800296 if (strcmp(usr_env_val, s_env_v)) {//need modify env in flash
297 MsgP("store env %s need modify\n", usr_env);
Bo Lv72d0e902023-01-02 14:27:34 +0000298 need_update_env = 1;
Sam Wu6f3d40e2023-04-22 01:10:27 +0800299 break;
Bo Lv72d0e902023-01-02 14:27:34 +0000300 }
Sam Wu6f3d40e2023-04-22 01:10:27 +0800301 debugP("store env %s NOT need update\n", usr_env);
302 ++n_same_env;
Bo Lv72d0e902023-01-02 14:27:34 +0000303 }
304 }
Sam Wu6f3d40e2023-04-22 01:10:27 +0800305 if (!need_update_env) {//old user env not changed
306 need_update_env = n_same_env < argc - 1;
307 debugP("usr env num %d, not need update %d\n", argc - 1, n_same_env);
308 }
309 //if all env not in flash, not need update if all env not exist
310 if (n_env_in_flash == 0) {//all env not in flash
311 int all_env_empty = 1;//all env not exist in flash, and in memory
312
313 for (i = 1; i < argc && all_env_empty; ++i)
314 if (env_get(argv[i]))
315 all_env_empty = 0;
316 if (all_env_empty)
317 if (!silent)
318 MsgP("all env not exist in env and flash\n");
319 need_update_env = !all_env_empty;
320 }
Bo Lv72d0e902023-01-02 14:27:34 +0000321 }
322
Sam Wu6f3d40e2023-04-22 01:10:27 +0800323 if (print)
324 run_command("printenv ${_update_env_list}", 0);
325 env_set("_update_env_list", NULL);
326 if (!need_update_env) {
327 MsgP("all env NOT need update\n");
328 ret = CMD_RET_SUCCESS; goto _update_env_part_err;
329 }
Bo Lv72d0e902023-01-02 14:27:34 +0000330
Sam Wu6f3d40e2023-04-22 01:10:27 +0800331 if (!n_env_in_flash) {//append all env to last as all not in env part
332 char *new_end = (char *)env_end;
333 unsigned int left_len = CONFIG_ENV_SIZE - env_len;
334
335 for (i = 1; i < argc && left_len > 0; ++i) {
336 char *usr_env = argv[i];
337 char *val = env_get(usr_env);
338 int cp_len = 0;
339
340 if (!val)
341 continue;
342 if (!silent)
343 MsgP("append new env %s\n", usr_env);
344 cp_len = strlcpy(++new_end, usr_env, left_len);//cp key
345 new_end += cp_len, left_len -= cp_len;
346 *new_end = '=', --left_len;//cpy '='
347 cp_len = strlcpy(++new_end, val, left_len) + 1;//cp val
348 new_end += cp_len, left_len -= cp_len;
349 }
350 if (left_len == CONFIG_ENV_SIZE - env_len) {
351 errorP("exception\n");
Bo Lv72d0e902023-01-02 14:27:34 +0000352 ret = CMD_RET_FAILURE; goto _update_env_part_err;
353 }
Sam Wu6f3d40e2023-04-22 01:10:27 +0800354 env_len = CONFIG_ENV_SIZE - left_len;
355 env_end = env_part_buf + env_len;
356
357 save_buf = 0; goto _update_env_save_;
358 } else {//not all env in flash
359 //copy flash env to new buf, and skip env need modify/delete
360 const char *current_kv = (char *)pdata;//env1=val\0
361 const char *kvsep = "=";
362 char *new_kv = new_env_buf;
363 unsigned int new_env_len = 0;
364 int env_need_update = 0;
365
366 memset(new_env_buf, 0, CONFIG_ENV_SIZE);
367 save_buf = 1;
368
369 /* 1, if current k=v\0 not in usr input list, just copy it to new buffer
370 * 2, else if in input list but no value, skip it
371 * 3, else if value not change, just copy it to new buffer
372 * 4, else if in the usr input list but value changed, use input key value instead
373 */
374 for (; current_kv < env_end; current_kv += strlen(current_kv) + 1) {
375 const char *s_env_v = strpbrk(current_kv, kvsep);//storage env value
376 const char *next = NULL;//next k=v
377 int s_env_v_len = 1;
378 unsigned int kv_len = 0;
379
380 if (!s_env_v) {
381 errorP("err env in flash, not k=v fmt\n%s\n", current_kv);
382 ret = CMD_RET_FAILURE; goto _update_env_part_err;
383 }
384 ++s_env_v;//skip '='
385 s_env_v_len = strnlen(s_env_v, env_end - s_env_v);
386 next = s_env_v + s_env_v_len + 1;//next k=v\0
387 for (i = 1; i < argc; ++i) {
388 const char *usr_env = argv[i];
389
390 if (!usr_env)
391 continue;//disposed
392 if (!strncmp(current_kv, usr_env, s_env_v - current_kv - 1))
393 break;
394 }
395 kv_len = (unsigned long)(next - current_kv);
396 if (i == argc) {//this store env not in user input, so not need change
397 memcpy(new_kv, current_kv, kv_len);
398 new_kv += kv_len;
399 new_env_len += kv_len;
400 } else {
401 const char *usr_env = argv[i];
402 const char *usr_env_val = env_get(usr_env);
403
404 if (!usr_env_val) {//2, in the input list but no value
405 MsgP("store env %s will removed\n", usr_env);
406 env_need_update = 1;
407 continue;
408 } else if (!strcmp(usr_env_val, s_env_v)) {//in input && not change
409 MsgP("store env %s not need changed\n", usr_env);
410 memcpy(new_kv, current_kv, kv_len);
411 new_kv += kv_len;
412 new_env_len += kv_len;
413 } else {//4, in the list and value changed
414 unsigned int cp_len = kv_len - 1 - s_env_v_len;
415
416 MsgP("store env %s DO need changed\n", usr_env);
417 env_need_update = 1;
418 memcpy(new_kv, current_kv, cp_len);//copy k=
419 new_kv += cp_len;
420 new_env_len += cp_len;
421
422 cp_len = strlen(usr_env_val) + 1;
423 memcpy(new_kv, usr_env_val, cp_len);//copy k=
424 new_kv += cp_len;
425 new_env_len += cp_len;
426 }
427 //argv[i] = NULL;//mark as disposed
428 *((char **)argv + i) = NULL;//mark as disposed
429 }
430 } //end to traverse all flash env
431
432 for (i = 1; i < argc; ++i) {
433 const char *usr_env = argv[i];
434 char *usr_env_val = usr_env ? env_get(usr_env) : NULL;
435 unsigned int left_len = 0;
436
437 if (!usr_env)
438 continue;
439 if (!usr_env_val) {
440 MsgP("new env %s NULL so skip\n", usr_env);
441 } else {
442 env_need_update = 1;
443 left_len = CONFIG_ENV_SIZE - new_env_len - 1;
444 snprintf(new_kv, left_len, "%s=%s", usr_env, usr_env_val);
445 MsgP("new store env %s\n", new_kv);
446 new_kv += strnlen(new_kv, left_len) + 1;
447 }
448 }
449 if (!env_need_update) {
450 MsgP("store env same, new env NULL, so not need update\n");
451 ret = CMD_RET_SUCCESS; goto _update_env_part_err;
452 }
Bo Lv72d0e902023-01-02 14:27:34 +0000453 }
454
Sam Wu6f3d40e2023-04-22 01:10:27 +0800455_update_env_save_:
456 ep = (env_t *)(env_part_buf + save_buf * CONFIG_ENV_SIZE);
457 pdata = ep->data;
458 debugP("crc before update 0x%x\n", ep->crc);
459
460 //ep->crc = crc32(0, pdata, ENV_SIZE);//not work...
461 crc = crc32(0, pdata, ENV_SIZE);
462 memcpy(&ep->crc, &crc, sizeof(crc));
463 if (!silent)
464 MsgP("new env part crc 0x%x\n", ep->crc);
465 if (store_rsv_write(RSV_ENV, CONFIG_ENV_SIZE, ep)) {
466 errorP("Fail to update env part\n");
Bo Lv72d0e902023-01-02 14:27:34 +0000467 ret = CMD_RET_FAILURE; goto _update_env_part_err;
468 }
Sam Wu6f3d40e2023-04-22 01:10:27 +0800469 debugP("ok update env addr 0x%p\n", env_part_buf);
Bo Lv72d0e902023-01-02 14:27:34 +0000470
471_update_env_part_err:
472 free(env_part_buf);
473 return ret;
474}
475
476U_BOOT_CMD_COMPLETE(update_env_part, //command name
477 CONFIG_SYS_MAXARGS, //maxargs
478 0, //repeatable
479 do_update_env_part, //command function
480 "update env part with argv list", //usage
481 " argv: update_env_part <-p> <-f> <-s> env0 env1 env2 ...\n"
482 " -p print, will print env value\n"
483 " -f force, will allow to update env part even some specified env vars not exist\n"
484 " -s silent, least log if specify -s\n"
485 " - e.g.\n"
486 " update_env_part -p lock:\n"
487 " update env var lock if it's diff in flash\n"
488 " update_env_part -f -p lock lock1:\n"
489 " update env var lock if it's diff and even lock1 is not exist\n",
490 var_complete
491);
492#endif //#if CONFIG_IS_ENABLED(AML_UPDATE_ENV)
493