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