1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2018 Linaro Ltd. 4 * Sam Protsenko <semen.protsenko@linaro.org> 5 * Eugeniu Rosca <rosca.eugeniu@gmail.com> 6 */ 7 8#include <command.h> 9#include <env.h> 10#include <image-android-dt.h> 11#include <common.h> 12 13#define OPT_INDEX "--index" 14 15/* 16 * Current/working DTB/DTBO Android image address. 17 * Similar to 'working_fdt' variable in 'fdt' command. 18 */ 19static ulong working_img; 20 21static int do_adtimg_addr(struct cmd_tbl *cmdtp, int flag, int argc, 22 char *const argv[]) 23{ 24 char *endp; 25 ulong hdr_addr; 26 27 if (argc != 2) 28 return CMD_RET_USAGE; 29 30 hdr_addr = hextoul(argv[1], &endp); 31 if (*endp != '\0') { 32 printf("Error: Wrong image address '%s'\n", argv[1]); 33 return CMD_RET_FAILURE; 34 } 35 36 /* 37 * Allow users to set an address prior to copying the DTB/DTBO 38 * image to that same address, i.e. skip header verification. 39 */ 40 41 working_img = hdr_addr; 42 return CMD_RET_SUCCESS; 43} 44 45static int adtimg_check_working_img(void) 46{ 47 if (!working_img) { 48 printf("Error: Please, call 'adtimg addr <addr>'. Aborting!\n"); 49 return CMD_RET_FAILURE; 50 } 51 52 if (!android_dt_check_header(working_img)) { 53 printf("Error: Invalid image header at 0x%lx\n", working_img); 54 return CMD_RET_FAILURE; 55 } 56 57 return CMD_RET_SUCCESS; 58} 59 60static int do_adtimg_dump(struct cmd_tbl *cmdtp, int flag, int argc, 61 char *const argv[]) 62{ 63 if (argc != 1) 64 return CMD_RET_USAGE; 65 66 if (adtimg_check_working_img() != CMD_RET_SUCCESS) 67 return CMD_RET_FAILURE; 68 69 android_dt_print_contents(working_img); 70 71 return CMD_RET_SUCCESS; 72} 73 74static int adtimg_getopt_u32(char * const opt, char * const name, u32 *optval) 75{ 76 char *endp, *str; 77 u32 val; 78 79 if (!opt || !name || !optval) 80 return CMD_RET_FAILURE; 81 82 str = strchr(opt, '='); 83 if (!str) { 84 printf("Error: Option '%s' not followed by '='\n", name); 85 return CMD_RET_FAILURE; 86 } 87 88 if (*++str == '\0') { 89 printf("Error: Option '%s=' not followed by value\n", name); 90 return CMD_RET_FAILURE; 91 } 92 93 val = simple_strtoul(str, &endp, 0); 94 if (*endp != '\0') { 95 printf("Error: Wrong integer value '%s=%s'\n", name, str); 96 return CMD_RET_FAILURE; 97 } 98 99 *optval = val; 100 return CMD_RET_SUCCESS; 101} 102 103static int adtimg_getopt_index(int argc, char *const argv[], u32 *index, 104 char **avar, char **svar) 105{ 106 int ret; 107 108 if (!argv || !avar || !svar) 109 return CMD_RET_FAILURE; 110 111 if (argc > 3) { 112 printf("Error: Unexpected argument '%s'\n", argv[3]); 113 return CMD_RET_FAILURE; 114 } 115 116 ret = adtimg_getopt_u32(argv[0], OPT_INDEX, index); 117 if (ret != CMD_RET_SUCCESS) 118 return ret; 119 120 if (argc > 1) 121 *avar = argv[1]; 122 if (argc > 2) 123 *svar = argv[2]; 124 125 return CMD_RET_SUCCESS; 126} 127 128static int adtimg_get_dt_by_index(int argc, char *const argv[]) 129{ 130 ulong addr; 131 u32 index, size; 132 int ret; 133 char *avar = NULL, *svar = NULL; 134 135 ret = adtimg_getopt_index(argc, argv, &index, &avar, &svar); 136 if (ret != CMD_RET_SUCCESS) 137 return ret; 138 139 if (!android_dt_get_fdt_by_index(working_img, index, &addr, &size)) 140 return CMD_RET_FAILURE; 141 142 if (avar && svar) { 143 ret = env_set_hex(avar, addr); 144 if (ret) { 145 printf("Error: Can't set '%s' to 0x%lx\n", avar, addr); 146 return CMD_RET_FAILURE; 147 } 148 ret = env_set_hex(svar, size); 149 if (ret) { 150 printf("Error: Can't set '%s' to 0x%x\n", svar, size); 151 return CMD_RET_FAILURE; 152 } 153 } else if (avar) { 154 ret = env_set_hex(avar, addr); 155 if (ret) { 156 printf("Error: Can't set '%s' to 0x%lx\n", avar, addr); 157 return CMD_RET_FAILURE; 158 } 159 printf("0x%x (%d)\n", size, size); 160 } else { 161 printf("0x%lx, 0x%x (%d)\n", addr, size, size); 162 } 163 164 return CMD_RET_SUCCESS; 165} 166 167static int adtimg_get_dt(int argc, char *const argv[]) 168{ 169 if (argc < 2) { 170 printf("Error: No options passed to '%s'\n", argv[0]); 171 return CMD_RET_FAILURE; 172 } 173 174 /* Strip off leading 'dt' command argument */ 175 argc--; 176 argv++; 177 178 if (!strncmp(argv[0], OPT_INDEX, sizeof(OPT_INDEX) - 1)) 179 return adtimg_get_dt_by_index(argc, argv); 180 181 printf("Error: Option '%s' not supported\n", argv[0]); 182 return CMD_RET_FAILURE; 183} 184 185static int do_adtimg_get(struct cmd_tbl *cmdtp, int flag, int argc, 186 char *const argv[]) 187{ 188 if (argc < 2) { 189 printf("Error: No arguments passed to '%s'\n", argv[0]); 190 return CMD_RET_FAILURE; 191 } 192 193 if (adtimg_check_working_img() != CMD_RET_SUCCESS) 194 return CMD_RET_FAILURE; 195 196 /* Strip off leading 'get' command argument */ 197 argc--; 198 argv++; 199 200 if (!strcmp(argv[0], "dt")) 201 return adtimg_get_dt(argc, argv); 202 203 printf("Error: Wrong argument '%s'\n", argv[0]); 204 return CMD_RET_FAILURE; 205} 206 207static struct cmd_tbl cmd_adtimg_sub[] = { 208 U_BOOT_CMD_MKENT(addr, CONFIG_SYS_MAXARGS, 1, do_adtimg_addr, "", ""), 209 U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_adtimg_dump, "", ""), 210 U_BOOT_CMD_MKENT(get, CONFIG_SYS_MAXARGS, 1, do_adtimg_get, "", ""), 211}; 212 213static int do_adtimg(struct cmd_tbl *cmdtp, int flag, int argc, 214 char *const argv[]) 215{ 216 struct cmd_tbl *cp; 217 218 cp = find_cmd_tbl(argv[1], cmd_adtimg_sub, ARRAY_SIZE(cmd_adtimg_sub)); 219 220 /* Strip off leading 'adtimg' command argument */ 221 argc--; 222 argv++; 223 224 if (!cp || argc > cp->maxargs) 225 return CMD_RET_USAGE; 226 if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) 227 return CMD_RET_SUCCESS; 228 229 return cp->cmd(cmdtp, flag, argc, argv); 230} 231 232U_BOOT_CMD( 233 adtimg, CONFIG_SYS_MAXARGS, 0, do_adtimg, 234 "manipulate dtb/dtbo Android image", 235 "addr <addr> - Set image location to <addr>\n" 236 "adtimg dump - Print out image contents\n" 237 "adtimg get dt --index=<index> [avar [svar]] - Get DT address/size by index\n" 238 "\n" 239 "Legend:\n" 240 " - <addr>: DTB/DTBO image address (hex) in RAM\n" 241 " - <index>: index (hex/dec) of desired DT in the image\n" 242 " - <avar>: variable name to contain DT address (hex)\n" 243 " - <svar>: variable name to contain DT size (hex)" 244); 245