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