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