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