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