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