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_offset, env_offset_redund; 19 static ulong env_size; 20 21 #ifdef CONFIG_SPL_BUILD 22 #ifdef CONFIG_SPL_ENV_PARTITION 23 /* 24 * In case of env and env-backup partitions are too large that exceeds the limit 25 * of CONFIG_SPL_SYS_MALLOC_F_LEN. we prefer to use a static address as an env 26 * buffer. The tail of bss section is good choice from experience. 27 */ 28 static void *env_buf = 29 (void *)CONFIG_SPL_BSS_START_ADDR + CONFIG_SPL_BSS_MAX_SIZE; 30 31 static const char *get_strval(env_t *env, u32 size, const char *str) 32 { 33 const char *dp; 34 u32 env_size; 35 36 dp = (const char *)env->data; 37 env_size = size - ENV_HEADER_SIZE; 38 do { 39 /* skip leading white space */ 40 while (*dp == ' ' || *dp == '\t') 41 ++dp; 42 43 debug("ENTRY: %s\n", dp); 44 if (strstr(dp, str)) { 45 debug("FIND: %s\n", dp); 46 return dp; 47 } 48 49 /* point to next ENTRY */ 50 dp += strlen(dp) + 1; 51 } while (((ulong)dp < (ulong)env->data + env_size) && *dp); 52 53 debug("NOT-FIND: %s\n", str); 54 55 return NULL; 56 } 57 58 static int env_do_load(struct blk_desc *desc, u32 offset, u32 size, 59 void *buf, void **envp) 60 { 61 lbaint_t env_size; 62 lbaint_t env_off; 63 env_t *env = buf; 64 u32 blk_cnt; 65 66 env_size = size - ENV_HEADER_SIZE; 67 env_off = BLK_CNT(desc, offset); 68 blk_cnt = BLK_CNT(desc, size); 69 70 if (blk_dread(desc, env_off, blk_cnt, (void *)env) != blk_cnt) { 71 ENVF_MSG("io error @ 0x%x\n", offset); 72 return -EIO; 73 } 74 75 if (crc32(0, env->data, env_size) != env->crc) { 76 ENVF_MSG("!bad CRC @ 0x%x\n", offset); 77 return -EINVAL; 78 } 79 80 if (envp) 81 *envp = env; 82 83 return 0; 84 } 85 86 int envf_load(struct blk_desc *desc) 87 { 88 const char *part_list; 89 int ret = -ENOENT; 90 void *env; 91 92 if (!desc) 93 return -ENODEV; 94 95 if (desc->if_type == IF_TYPE_MTD && 96 (desc->devnum == BLK_MTD_SPI_NAND || desc->devnum == BLK_MTD_NAND)) { 97 env_size = CONFIG_ENV_NAND_SIZE; 98 env_offset = CONFIG_ENV_NAND_OFFSET; 99 env_offset_redund = CONFIG_ENV_NAND_OFFSET_REDUND; 100 } else { 101 env_size = CONFIG_ENV_SIZE; 102 env_offset = CONFIG_ENV_OFFSET; 103 env_offset_redund = CONFIG_ENV_OFFSET_REDUND; 104 } 105 106 if (env_offset == env_offset_redund) 107 env_offset_redund = 0; 108 109 ENVF_MSG("Primary 0x%08lx - 0x%08lx\n", env_offset, env_offset + env_size); 110 if (env_offset_redund) 111 ENVF_MSG("Backup 0x%08lx - 0x%08lx\n", 112 env_offset_redund, env_offset_redund + env_size); 113 114 ret = env_do_load(desc, env_offset, env_size, env_buf, &env); 115 if (ret < 0 && env_offset_redund) 116 ret = env_do_load(desc, env_offset_redund, env_size, 117 env_buf + env_size, &env); 118 if (ret < 0) { 119 ENVF_MSG("No valid env data, ret=%d\n", ret); 120 return ret; 121 } 122 123 part_list = get_strval(env, env_size, "mtdparts"); 124 if (!part_list) 125 part_list = get_strval(env, env_size, "blkdevparts"); 126 if (!part_list) { 127 ENVF_MSG("No valid env part list\n"); 128 return ret; 129 } 130 131 ENVF_MSG("OK\n"); 132 env_part_list_init(part_list); 133 /* 134 * Call blk_dread() to read env content: 135 * => mmc_init() => part_init() with CONFIG_ENV_PARTITION_LIST => mmc init ok 136 * => read env content! including partition tables(blkdevparts/mtdparts). 137 * 138 * So we must reinit env partition after we setup the partition 139 * tables(blkdevparts/mtdparts) from env. 140 */ 141 part_init(desc); 142 143 return 0; 144 } 145 #endif 146 147 #else 148 /* 149 * Example: ./tools/mkenvimage -s 0x8000 -p 0x0 -o env.img env.txt 150 */ 151 #define ENVF_MAX 64 152 #define ENVF_EMSG "error: please use \"sys_bootargs\" but not " \ 153 "\"bootargs\" in CONFIG_ENVF_LIST and envf.bin" 154 static const char *envf_list[ENVF_MAX]; 155 static u32 envf_num; 156 157 static int envf_extract_list(void) 158 { 159 char *tok, *p; 160 u32 i = 0; 161 162 tok = strdup(CONFIG_ENVF_LIST); 163 if (!tok) 164 return -ENOMEM; 165 166 p = strtok(tok, " "); 167 while (p && i < ENVF_MAX) { 168 if (!strcmp(p, "bootargs")) { 169 printf("%s\n", ENVF_EMSG); 170 run_command("download", 0); 171 } 172 envf_list[i++] = p; 173 p = strtok(NULL, " "); 174 } 175 176 envf_num = i; 177 178 return 0; 179 } 180 181 static int env_do_load(struct blk_desc *desc, u32 offset, u32 size, 182 const char *list[], int num, void **envp) 183 { 184 ALLOC_CACHE_ALIGN_BUFFER(env_t, env, 1); 185 lbaint_t env_size; 186 lbaint_t env_off; 187 u32 blk_cnt; 188 int ret = 0; 189 190 env_size = size - ENV_HEADER_SIZE; 191 env_off = BLK_CNT(desc, offset); 192 blk_cnt = BLK_CNT(desc, size); 193 194 if (blk_dread(desc, env_off, blk_cnt, (void *)env) != blk_cnt) { 195 ret = -EIO; 196 goto out; 197 } 198 199 if (crc32(0, env->data, env_size) != env->crc) { 200 ENVF_MSG("!bad CRC @ 0x%x\n", offset); 201 ret = -EINVAL; 202 goto out; 203 } 204 205 if (!himport_r(&env_htab, (char *)env->data, env_size, '\0', 206 H_NOCLEAR, 0, num, (char * const *)list)) { 207 ENVF_MSG("himport error: %d\n", errno); 208 ret = -EINTR; 209 } 210 211 if (envp) 212 *envp = env; 213 out: 214 return ret; 215 } 216 217 static int envf_load(void) 218 { 219 struct blk_desc *desc; 220 int ret = -ENOENT; 221 222 desc = rockchip_get_bootdev(); 223 if (!desc) { 224 printf("dev desc null!\n"); 225 return 0; 226 } 227 228 if (desc->if_type == IF_TYPE_MTD && 229 (desc->devnum == BLK_MTD_SPI_NAND || desc->devnum == BLK_MTD_NAND)) { 230 env_size = CONFIG_ENV_NAND_SIZE; 231 env_offset = CONFIG_ENV_NAND_OFFSET; 232 env_offset_redund = CONFIG_ENV_NAND_OFFSET_REDUND; 233 } else { 234 env_size = CONFIG_ENV_SIZE; 235 env_offset = CONFIG_ENV_OFFSET; 236 env_offset_redund = CONFIG_ENV_OFFSET_REDUND; 237 } 238 239 if (env_offset == env_offset_redund) 240 env_offset_redund = 0; 241 242 ENVF_MSG("Primary 0x%08lx - 0x%08lx\n", env_offset, env_offset + env_size); 243 if (env_offset_redund) 244 ENVF_MSG("Backup 0x%08lx - 0x%08lx\n", 245 env_offset_redund, env_offset_redund + env_size); 246 247 envf_extract_list(); 248 ret = env_do_load(desc, env_offset, env_size, envf_list, envf_num, NULL); 249 if (ret < 0 && env_offset_redund) { 250 ret = env_do_load(desc, env_offset_redund, 251 env_size, envf_list, envf_num, NULL); 252 } 253 if (ret < 0) { 254 ENVF_MSG("No valid env data, ret=%d\n", ret); 255 return ret; 256 } 257 258 ENVF_MSG("OK\n"); 259 printf(" - %s\n", CONFIG_ENVF_LIST); 260 #ifdef CONFIG_ENV_PARTITION 261 /* 262 * Call blk_dread() to read envf content: 263 * => mmc_init() => part_init() with CONFIG_ENV_PARTITION_LIST => mmc init ok 264 * => read envf content! including partition tables(blkdevparts/mtdparts). 265 * 266 * So we must reinit env partition after we setup the partition 267 * tables(blkdevparts/mtdparts) from envf. 268 */ 269 part_init(desc); 270 #endif 271 return 0; 272 } 273 274 static int envf_save(void) 275 { 276 ALLOC_CACHE_ALIGN_BUFFER(env_t, env, 1); 277 struct blk_desc *desc; 278 u32 blk_cnt; 279 ssize_t len; 280 char *res; 281 int ret = 0; 282 283 desc = rockchip_get_bootdev(); 284 if (!desc) { 285 printf("dev desc null!\n"); 286 return -EINVAL; 287 } 288 289 res = (char *)env->data; 290 len = hexport_r(&env_htab, '\0', H_MATCH_KEY | H_MATCH_IDENT, 291 &res, env_size - ENV_HEADER_SIZE, 292 envf_num, (char * const *)envf_list); 293 if (len < 0) { 294 ENVF_MSG("hexpor error: %d\n", errno); 295 return -EINVAL; 296 } 297 298 env->crc = crc32(0, env->data, env_size - ENV_HEADER_SIZE); 299 blk_cnt = BLK_CNT(desc, env_size); 300 if (blk_dwrite(desc, BLK_CNT(desc, env_offset), 301 blk_cnt, (char *)env) != blk_cnt) { 302 ret = -EIO; 303 ENVF_MSG("io error\n"); 304 } 305 306 if (env_offset_redund) { 307 if (blk_dwrite(desc, BLK_CNT(desc, env_offset_redund), 308 blk_cnt, (char *)env) != blk_cnt) 309 ENVF_MSG("redundant: io error\n"); 310 else 311 ret = 0; 312 } 313 314 return ret; 315 } 316 317 static int envf_nowhere_init(void) 318 { 319 gd->env_addr = (ulong)&default_environment[0]; 320 gd->env_valid = ENV_INVALID; 321 322 return 0; 323 } 324 325 U_BOOT_ENV_LOCATION(nowhere) = { 326 .location = ENVL_NOWHERE, 327 .init = envf_nowhere_init, 328 .load = envf_load, 329 .save = env_save_ptr(envf_save), 330 ENV_NAME("envf") 331 }; 332 #endif 333