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