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 #define ENVPARAM_SIZE SZ_4K 18 19 static ulong env_offset, env_offset_redund; 20 static ulong env_size; 21 static u32 envparam_addr_common[] = { 0, SZ_4K }; 22 static u32 envparam_addr_spinand[] = { 0, SZ_256K }; 23 24 #ifdef CONFIG_SPL_BUILD 25 #ifdef CONFIG_SPL_ENV_PARTITION 26 static const char *get_strval(env_t *env, u32 size, const char *str) 27 { 28 const char *dp; 29 u32 env_size; 30 31 dp = (const char *)env->data; 32 env_size = size - ENV_HEADER_SIZE; 33 do { 34 /* skip leading white space */ 35 while (*dp == ' ' || *dp == '\t') 36 ++dp; 37 38 debug("ENTRY: %s\n", dp); 39 if (strstr(dp, str)) { 40 debug("FIND: %s\n", dp); 41 return dp; 42 } 43 44 /* point to next ENTRY */ 45 dp += strlen(dp) + 1; 46 } while (((ulong)dp < (ulong)env->data + env_size) && *dp); 47 48 debug("NOT-FIND: %s\n", str); 49 50 return NULL; 51 } 52 53 static ulong get_strval_ulong(env_t *env, u32 size, 54 const char *str, ulong default_val) 55 { 56 const char *p; 57 58 p = get_strval(env, size, str); 59 if (!p) 60 return default_val; 61 p = strstr(p, "="); 62 if (!p) 63 return default_val; 64 65 ++p; /* skip '=' */ 66 67 return simple_strtoul(p, NULL, 16); 68 } 69 70 static int env_do_load(struct blk_desc *desc, u32 offset, u32 size, void **envp) 71 { 72 lbaint_t env_size; 73 lbaint_t env_off; 74 u32 blk_cnt; 75 env_t *env; 76 77 env_size = size - ENV_HEADER_SIZE; 78 env_off = BLK_CNT(desc, offset); 79 blk_cnt = BLK_CNT(desc, size); 80 81 env = memalign(ARCH_DMA_MINALIGN, size); 82 if (!env) 83 return -ENOMEM; 84 85 if (blk_dread(desc, env_off, blk_cnt, (void *)env) != blk_cnt) { 86 ENVF_MSG("io error @ 0x%x\n", offset); 87 free(env); 88 return -EIO; 89 } 90 91 if (crc32(0, env->data, env_size) != env->crc) { 92 ENVF_MSG("!bad CRC @ 0x%x\n", offset); 93 free(env); 94 return -EINVAL; 95 } 96 97 if (envp) 98 *envp = env; 99 100 return 0; 101 } 102 103 int envf_load(struct blk_desc *desc) 104 { 105 void *env, *envp0, *envp1; 106 const char *part_list; 107 int read0_fail, read1_fail; 108 int envp_blks; 109 int ret = -ENOENT; 110 u32 *addr; 111 112 if (!desc) 113 return -ENODEV; 114 115 /* Import envparam */ 116 if (desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NAND) 117 addr = envparam_addr_spinand; 118 else 119 addr = envparam_addr_common; 120 121 envp_blks = BLK_CNT(desc, ENVPARAM_SIZE); 122 read0_fail = env_do_load(desc, addr[0], ENVPARAM_SIZE, &envp0); 123 read1_fail = env_do_load(desc, addr[1], ENVPARAM_SIZE, &envp1); 124 if (read0_fail && read1_fail) { 125 ENVF_MSG("No valid envparam!\n"); 126 } else if (!read0_fail && read1_fail) { 127 env = envp0; 128 ret = blk_dwrite(desc, BLK_CNT(desc, addr[1]), 129 BLK_CNT(desc, ENVPARAM_SIZE), envp0); 130 printf("Repair backup envparam %s\n", 131 ret == envp_blks ? "ok" : "fail"); 132 } else if (read0_fail && !read1_fail) { 133 env = envp1; 134 ret = blk_dwrite(desc, BLK_CNT(desc, addr[0]), 135 BLK_CNT(desc, ENVPARAM_SIZE), envp1); 136 printf("Repair primary envparam %s\n", 137 ret == envp_blks ? "ok" : "fail"); 138 } else { 139 env = envp0; /* both ok, use primary envparam */ 140 } 141 142 /* Import env data */ 143 env_size = get_strval_ulong(env, ENVPARAM_SIZE, "ENV_SIZE", 0); 144 env_offset = get_strval_ulong(env, ENVPARAM_SIZE, "ENV_OFFSET", 0); 145 env_offset_redund = get_strval_ulong(env, ENVPARAM_SIZE, "ENV_OFFSET_REDUND", 0); 146 if (!env_offset || !env_size) { 147 ENVF_MSG("Invalid env offset/size, use default\n"); 148 env_offset = CONFIG_ENV_OFFSET; 149 env_size = CONFIG_ENV_SIZE; 150 #if (CONFIG_ENV_OFFSET_REDUND != CONFIG_ENV_OFFSET) 151 env_offset_redund = CONFIG_ENV_OFFSET_REDUND; 152 #endif 153 } 154 155 printf("ENVF: 0x%08lx - 0x%08lx\n", env_offset, env_offset + env_size); 156 if (env_offset_redund) 157 printf("ENVF Backup: 0x%08lx - 0x%08lx\n", 158 env_offset_redund, env_offset_redund + env_size); 159 160 ret = env_do_load(desc, env_offset, env_size, &env); 161 if (ret < 0 && env_offset_redund) 162 ret = env_do_load(desc, env_offset_redund, env_size, &env); 163 if (ret < 0) { 164 ENVF_MSG("No valid env data, ret=%d\n", ret); 165 return ret; 166 } 167 168 part_list = get_strval(env, env_size, "mtdparts"); 169 if (!part_list) 170 part_list = get_strval(env, env_size, "blkdevparts"); 171 if (!part_list) { 172 ENVF_MSG("No valid env part list\n"); 173 return ret; 174 } 175 176 ENVF_MSG("OK\n"); 177 env_part_list_init(part_list); 178 /* 179 * Call blk_dread() to read env content: 180 * => mmc_init() => part_init() with CONFIG_ENV_PARTITION_LIST => mmc init ok 181 * => read env content! including partition tables(blkdevparts/mtdparts). 182 * 183 * So we must reinit env partition after we setup the partition 184 * tables(blkdevparts/mtdparts) from env. 185 */ 186 part_init(desc); 187 188 return 0; 189 } 190 #endif 191 192 #else 193 /* 194 * [Example] 195 * generate envparam: 196 * ./tools/mkenvimage -s 0x1000 -p 0x0 -o envparam.bin envparam.txt 197 * generate data: 198 * ./tools/mkenvimage -s 0x8000 -p 0x0 -o envf.bin envf.txt 199 */ 200 #define ENVF_MAX 64 201 #define ENVF_EMSG "error: please use \"sys_bootargs\" but not " \ 202 "\"bootargs\" in CONFIG_ENVF_LIST and envf.bin" 203 static const char *envf_list[ENVF_MAX]; 204 static u32 envf_num; 205 206 static int envf_extract_list(void) 207 { 208 char *tok, *p; 209 u32 i = 0; 210 211 tok = strdup(CONFIG_ENVF_LIST); 212 if (!tok) 213 return -ENOMEM; 214 215 p = strtok(tok, " "); 216 while (p && i < ENVF_MAX) { 217 if (!strcmp(p, "bootargs")) { 218 printf("%s\n", ENVF_EMSG); 219 run_command("download", 0); 220 } 221 envf_list[i++] = p; 222 p = strtok(NULL, " "); 223 } 224 225 envf_num = i; 226 227 return 0; 228 } 229 230 static int env_do_load(struct blk_desc *desc, u32 offset, u32 size, 231 const char *list[], int num, void **envp) 232 { 233 lbaint_t env_size; 234 lbaint_t env_off; 235 u32 blk_cnt; 236 int ret = 0; 237 env_t *env; 238 239 env_size = size - ENV_HEADER_SIZE; 240 env_off = BLK_CNT(desc, offset); 241 blk_cnt = BLK_CNT(desc, size); 242 243 env = memalign(ARCH_DMA_MINALIGN, size); 244 if (!env) 245 return -ENOMEM; 246 247 if (blk_dread(desc, env_off, blk_cnt, (void *)env) != blk_cnt) { 248 ret = -EIO; 249 goto out; 250 } 251 252 if (crc32(0, env->data, env_size) != env->crc) { 253 ENVF_MSG("!bad CRC @ 0x%x\n", offset); 254 ret = -EINVAL; 255 goto out; 256 } 257 258 if (!himport_r(&env_htab, (char *)env->data, env_size, '\0', 259 H_NOCLEAR, 0, num, (char * const *)list)) { 260 ENVF_MSG("himport error: %d\n", errno); 261 ret = -EINTR; 262 } 263 264 if (envp) 265 *envp = env; 266 out: 267 return ret; 268 } 269 270 static int envf_load(void) 271 { 272 const char *envparam[] = { 273 "ENV_OFFSET", "ENV_SIZE", "ENV_OFFSET_REDUND", 274 }; 275 struct blk_desc *desc; 276 int read0_fail, read1_fail; 277 int envp_blks; 278 void *envp0 = NULL; 279 void *envp1 = NULL; 280 int ret = -ENOENT; 281 u32 *addr; 282 283 desc = rockchip_get_bootdev(); 284 if (!desc) { 285 printf("dev desc null!\n"); 286 return 0; 287 } 288 289 /* Import envparam */ 290 if (desc->if_type == IF_TYPE_MTD && desc->devnum == BLK_MTD_SPI_NAND) 291 addr = envparam_addr_spinand; 292 else 293 addr = envparam_addr_common; 294 295 envp_blks = BLK_CNT(desc, ENVPARAM_SIZE); 296 read0_fail = env_do_load(desc, addr[0], ENVPARAM_SIZE, 297 envparam, ARRAY_SIZE(envparam), &envp0); 298 read1_fail = env_do_load(desc, addr[1], ENVPARAM_SIZE, 299 envparam, ARRAY_SIZE(envparam), &envp1); 300 if (read0_fail && read1_fail) { 301 ENVF_MSG("No valid envparam!\n"); 302 } else if (!read0_fail && read1_fail) { 303 ret = blk_dwrite(desc, BLK_CNT(desc, addr[1]), 304 BLK_CNT(desc, ENVPARAM_SIZE), envp0); 305 printf("Repair backup envparam %s\n", 306 ret == envp_blks ? "ok" : "fail"); 307 } else if (read0_fail && !read1_fail) { 308 ret = blk_dwrite(desc, BLK_CNT(desc, addr[0]), 309 BLK_CNT(desc, ENVPARAM_SIZE), envp1); 310 printf("Repair primary envparam %s\n", 311 ret == envp_blks ? "ok" : "fail"); 312 } 313 314 if (envp0) 315 free(envp0); 316 if (envp1) 317 free(envp1); 318 319 /* Import env data */ 320 env_size = env_get_ulong("ENV_SIZE", 16, 0); 321 env_offset = env_get_ulong("ENV_OFFSET", 16, 0); 322 env_offset_redund = env_get_ulong("ENV_OFFSET_REDUND", 16, 0); 323 if (!env_offset || !env_size) { 324 ENVF_MSG("Invalid env offset/size, use default\n"); 325 env_offset = CONFIG_ENV_OFFSET; 326 env_size = CONFIG_ENV_SIZE; 327 #if (CONFIG_ENV_OFFSET_REDUND != CONFIG_ENV_OFFSET) 328 env_offset_redund = CONFIG_ENV_OFFSET_REDUND; 329 #endif 330 } 331 332 printf("ENVF: 0x%08lx - 0x%08lx\n", env_offset, env_offset + env_size); 333 if (env_offset_redund) 334 printf("ENVF Backup: 0x%08lx - 0x%08lx\n", 335 env_offset_redund, env_offset_redund + env_size); 336 337 envf_extract_list(); 338 ret = env_do_load(desc, env_offset, env_size, envf_list, envf_num, NULL); 339 if (ret < 0 && env_offset_redund) { 340 ret = env_do_load(desc, env_offset_redund, 341 env_size, envf_list, envf_num, NULL); 342 } 343 if (ret < 0) { 344 ENVF_MSG("No valid env data, ret=%d\n", ret); 345 return ret; 346 } 347 348 ENVF_MSG("OK\n"); 349 printf(" - %s\n", CONFIG_ENVF_LIST); 350 #ifdef CONFIG_ENV_PARTITION 351 /* 352 * Call blk_dread() to read envf content: 353 * => mmc_init() => part_init() with CONFIG_ENV_PARTITION_LIST => mmc init ok 354 * => read envf content! including partition tables(blkdevparts/mtdparts). 355 * 356 * So we must reinit env partition after we setup the partition 357 * tables(blkdevparts/mtdparts) from envf. 358 */ 359 part_init(desc); 360 #endif 361 return 0; 362 } 363 364 static int envf_save(void) 365 { 366 ALLOC_CACHE_ALIGN_BUFFER(env_t, env, 1); 367 struct blk_desc *desc; 368 u32 blk_cnt; 369 ssize_t len; 370 char *res; 371 int ret = 0; 372 373 desc = rockchip_get_bootdev(); 374 if (!desc) { 375 printf("dev desc null!\n"); 376 return -EINVAL; 377 } 378 379 res = (char *)env->data; 380 len = hexport_r(&env_htab, '\0', H_MATCH_KEY | H_MATCH_IDENT, 381 &res, env_size - ENV_HEADER_SIZE, 382 envf_num, (char * const *)envf_list); 383 if (len < 0) { 384 ENVF_MSG("hexpor error: %d\n", errno); 385 return -EINVAL; 386 } 387 388 env->crc = crc32(0, env->data, env_size - ENV_HEADER_SIZE); 389 blk_cnt = BLK_CNT(desc, env_size); 390 if (blk_dwrite(desc, BLK_CNT(desc, env_offset), 391 blk_cnt, (char *)env) != blk_cnt) { 392 ret = -EIO; 393 ENVF_MSG("io error\n"); 394 } 395 396 if (env_offset_redund) { 397 if (blk_dwrite(desc, BLK_CNT(desc, env_offset_redund), 398 blk_cnt, (char *)env) != blk_cnt) 399 ENVF_MSG("redundant: io error\n"); 400 else 401 ret = 0; 402 } 403 404 return ret; 405 } 406 407 static int envf_nowhere_init(void) 408 { 409 gd->env_addr = (ulong)&default_environment[0]; 410 gd->env_valid = ENV_INVALID; 411 412 return 0; 413 } 414 415 U_BOOT_ENV_LOCATION(nowhere) = { 416 .location = ENVL_NOWHERE, 417 .init = envf_nowhere_init, 418 .load = envf_load, 419 .save = env_save_ptr(envf_save), 420 ENV_NAME("envf") 421 }; 422 #endif 423