Blame view
cmd/bcb.c
7.67 KB
db7b7a05b cmd: Add 'bcb' co... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2019 Eugeniu Rosca <rosca.eugeniu@gmail.com> * * Command to read/modify/write Android BCB fields */ #include <android_bootloader_message.h> #include <command.h> #include <common.h> enum bcb_cmd { BCB_CMD_LOAD, BCB_CMD_FIELD_SET, BCB_CMD_FIELD_CLEAR, BCB_CMD_FIELD_TEST, BCB_CMD_FIELD_DUMP, BCB_CMD_STORE, }; static int bcb_dev = -1; static int bcb_part = -1; static struct bootloader_message bcb = { { 0 } }; static int bcb_cmd_get(char *cmd) { |
739168cfd cmd: bcb: Use str... |
27 |
if (!strcmp(cmd, "load")) |
db7b7a05b cmd: Add 'bcb' co... |
28 |
return BCB_CMD_LOAD; |
739168cfd cmd: bcb: Use str... |
29 |
if (!strcmp(cmd, "set")) |
db7b7a05b cmd: Add 'bcb' co... |
30 |
return BCB_CMD_FIELD_SET; |
739168cfd cmd: bcb: Use str... |
31 |
if (!strcmp(cmd, "clear")) |
db7b7a05b cmd: Add 'bcb' co... |
32 |
return BCB_CMD_FIELD_CLEAR; |
739168cfd cmd: bcb: Use str... |
33 |
if (!strcmp(cmd, "test")) |
db7b7a05b cmd: Add 'bcb' co... |
34 |
return BCB_CMD_FIELD_TEST; |
739168cfd cmd: bcb: Use str... |
35 |
if (!strcmp(cmd, "store")) |
db7b7a05b cmd: Add 'bcb' co... |
36 |
return BCB_CMD_STORE; |
739168cfd cmd: bcb: Use str... |
37 |
if (!strcmp(cmd, "dump")) |
db7b7a05b cmd: Add 'bcb' co... |
38 39 40 41 42 43 44 45 46 47 48 |
return BCB_CMD_FIELD_DUMP; else return -1; } static int bcb_is_misused(int argc, char *const argv[]) { int cmd = bcb_cmd_get(argv[0]); switch (cmd) { case BCB_CMD_LOAD: |
db7b7a05b cmd: Add 'bcb' co... |
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
case BCB_CMD_FIELD_SET: if (argc != 3) goto err; break; case BCB_CMD_FIELD_TEST: if (argc != 4) goto err; break; case BCB_CMD_FIELD_CLEAR: if (argc != 1 && argc != 2) goto err; break; case BCB_CMD_STORE: if (argc != 1) goto err; break; case BCB_CMD_FIELD_DUMP: if (argc != 2) goto err; break; default: printf("Error: 'bcb %s' not supported ", argv[0]); return -1; } if (cmd != BCB_CMD_LOAD && (bcb_dev < 0 || bcb_part < 0)) { printf("Error: Please, load BCB first! "); return -1; } return 0; err: printf("Error: Bad usage of 'bcb %s' ", argv[0]); return -1; } |
37f1811a0 cmd: bcb: Apply n... |
88 |
static int bcb_field_get(char *name, char **fieldp, int *sizep) |
db7b7a05b cmd: Add 'bcb' co... |
89 |
{ |
739168cfd cmd: bcb: Use str... |
90 |
if (!strcmp(name, "command")) { |
37f1811a0 cmd: bcb: Apply n... |
91 92 |
*fieldp = bcb.command; *sizep = sizeof(bcb.command); |
739168cfd cmd: bcb: Use str... |
93 |
} else if (!strcmp(name, "status")) { |
37f1811a0 cmd: bcb: Apply n... |
94 95 |
*fieldp = bcb.status; *sizep = sizeof(bcb.status); |
739168cfd cmd: bcb: Use str... |
96 |
} else if (!strcmp(name, "recovery")) { |
37f1811a0 cmd: bcb: Apply n... |
97 98 |
*fieldp = bcb.recovery; *sizep = sizeof(bcb.recovery); |
739168cfd cmd: bcb: Use str... |
99 |
} else if (!strcmp(name, "stage")) { |
37f1811a0 cmd: bcb: Apply n... |
100 101 |
*fieldp = bcb.stage; *sizep = sizeof(bcb.stage); |
739168cfd cmd: bcb: Use str... |
102 |
} else if (!strcmp(name, "reserved")) { |
37f1811a0 cmd: bcb: Apply n... |
103 104 |
*fieldp = bcb.reserved; *sizep = sizeof(bcb.reserved); |
db7b7a05b cmd: Add 'bcb' co... |
105 106 107 108 109 110 111 112 |
} else { printf("Error: Unknown bcb field '%s' ", name); return -1; } return 0; } |
37f1811a0 cmd: bcb: Apply n... |
113 114 |
static int do_bcb_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
db7b7a05b cmd: Add 'bcb' co... |
115 116 117 118 119 120 121 122 123 |
{ struct blk_desc *desc; disk_partition_t info; u64 cnt; char *endp; int part, ret; ret = blk_get_device_by_str("mmc", argv[1], &desc); if (ret < 0) |
37f1811a0 cmd: bcb: Apply n... |
124 |
goto err_read_fail; |
db7b7a05b cmd: Add 'bcb' co... |
125 126 127 128 129 |
part = simple_strtoul(argv[2], &endp, 0); if (*endp == '\0') { ret = part_get_info(desc, part, &info); if (ret) |
37f1811a0 cmd: bcb: Apply n... |
130 |
goto err_read_fail; |
db7b7a05b cmd: Add 'bcb' co... |
131 132 133 134 |
} else { part = part_get_info_by_name(desc, argv[2], &info); if (part < 0) { ret = part; |
37f1811a0 cmd: bcb: Apply n... |
135 |
goto err_read_fail; |
db7b7a05b cmd: Add 'bcb' co... |
136 137 138 139 140 |
} } cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), info.blksz); if (cnt > info.size) |
37f1811a0 cmd: bcb: Apply n... |
141 |
goto err_too_small; |
db7b7a05b cmd: Add 'bcb' co... |
142 143 144 |
if (blk_dread(desc, info.start, cnt, &bcb) != cnt) { ret = -EIO; |
37f1811a0 cmd: bcb: Apply n... |
145 |
goto err_read_fail; |
db7b7a05b cmd: Add 'bcb' co... |
146 147 148 149 150 151 152 153 |
} bcb_dev = desc->devnum; bcb_part = part; debug("%s: Loaded from mmc %d:%d ", __func__, bcb_dev, bcb_part); return CMD_RET_SUCCESS; |
37f1811a0 cmd: bcb: Apply n... |
154 |
err_read_fail: |
db7b7a05b cmd: Add 'bcb' co... |
155 156 157 |
printf("Error: mmc %s:%s read failed (%d) ", argv[1], argv[2], ret); goto err; |
37f1811a0 cmd: bcb: Apply n... |
158 |
err_too_small: |
db7b7a05b cmd: Add 'bcb' co... |
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 |
printf("Error: mmc %s:%s too small!", argv[1], argv[2]); goto err; err: bcb_dev = -1; bcb_part = -1; return CMD_RET_FAILURE; } static int do_bcb_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int size, len; char *field, *str, *found; if (bcb_field_get(argv[1], &field, &size)) return CMD_RET_FAILURE; len = strlen(argv[2]); if (len >= size) { printf("Error: sizeof('%s') = %d >= %d = sizeof(bcb.%s) ", argv[2], len, size, argv[1]); return CMD_RET_FAILURE; } str = argv[2]; field[0] = '\0'; while ((found = strsep(&str, ":"))) { if (field[0] != '\0') strcat(field, " "); strcat(field, found); } return CMD_RET_SUCCESS; } static int do_bcb_clear(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int size; char *field; if (argc == 1) { memset(&bcb, 0, sizeof(bcb)); return CMD_RET_SUCCESS; } if (bcb_field_get(argv[1], &field, &size)) return CMD_RET_FAILURE; memset(field, 0, size); return CMD_RET_SUCCESS; } static int do_bcb_test(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int size; char *field; char *op = argv[2]; if (bcb_field_get(argv[1], &field, &size)) return CMD_RET_FAILURE; if (*op == '=' && *(op + 1) == '\0') { if (!strncmp(argv[3], field, size)) return CMD_RET_SUCCESS; else return CMD_RET_FAILURE; } else if (*op == '~' && *(op + 1) == '\0') { if (!strstr(field, argv[3])) return CMD_RET_FAILURE; else return CMD_RET_SUCCESS; } else { printf("Error: Unknown operator '%s' ", op); } return CMD_RET_FAILURE; } static int do_bcb_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int size; char *field; if (bcb_field_get(argv[1], &field, &size)) return CMD_RET_FAILURE; print_buffer((ulong)field - (ulong)&bcb, (void *)field, 1, size, 16); return CMD_RET_SUCCESS; } static int do_bcb_store(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { struct blk_desc *desc; disk_partition_t info; u64 cnt; int ret; desc = blk_get_devnum_by_type(IF_TYPE_MMC, bcb_dev); if (!desc) { ret = -ENODEV; goto err; } ret = part_get_info(desc, bcb_part, &info); if (ret) goto err; cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), info.blksz); if (blk_dwrite(desc, info.start, cnt, &bcb) != cnt) { ret = -EIO; goto err; } return CMD_RET_SUCCESS; err: printf("Error: mmc %d:%d write failed (%d) ", bcb_dev, bcb_part, ret); return CMD_RET_FAILURE; } static cmd_tbl_t cmd_bcb_sub[] = { U_BOOT_CMD_MKENT(load, CONFIG_SYS_MAXARGS, 1, do_bcb_load, "", ""), U_BOOT_CMD_MKENT(set, CONFIG_SYS_MAXARGS, 1, do_bcb_set, "", ""), U_BOOT_CMD_MKENT(clear, CONFIG_SYS_MAXARGS, 1, do_bcb_clear, "", ""), U_BOOT_CMD_MKENT(test, CONFIG_SYS_MAXARGS, 1, do_bcb_test, "", ""), U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_bcb_dump, "", ""), U_BOOT_CMD_MKENT(store, CONFIG_SYS_MAXARGS, 1, do_bcb_store, "", ""), }; static int do_bcb(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { cmd_tbl_t *c; if (argc < 2) return CMD_RET_USAGE; argc--; argv++; c = find_cmd_tbl(argv[0], cmd_bcb_sub, ARRAY_SIZE(cmd_bcb_sub)); if (!c) return CMD_RET_USAGE; if (bcb_is_misused(argc, argv)) { |
37f1811a0 cmd: bcb: Apply n... |
315 316 |
/* * We try to improve the user experience by reporting the |
db7b7a05b cmd: Add 'bcb' co... |
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
* root-cause of misusage, so don't return CMD_RET_USAGE, * since the latter prints out the full-blown help text */ return CMD_RET_FAILURE; } return c->cmd(cmdtp, flag, argc, argv); } U_BOOT_CMD( bcb, CONFIG_SYS_MAXARGS, 1, do_bcb, "Load/set/clear/test/dump/store Android BCB fields", "load <dev> <part> - load BCB from mmc <dev>:<part> " "bcb set <field> <val> - set BCB <field> to <val> " "bcb clear [<field>] - clear BCB <field> or all fields " "bcb test <field> <op> <val> - test BCB <field> against <val> " "bcb dump <field> - dump BCB <field> " "bcb store - store BCB back to mmc " " " "Legend: " "<dev> - MMC device index containing the BCB partition " "<part> - MMC partition index or name containing the BCB " "<field> - one of {command,status,recovery,stage,reserved} " "<op> - the binary operator used in 'bcb test': " " '=' returns true if <val> matches the string stored in <field> " " '~' returns true if <val> matches a subset of <field>'s string " "<val> - string/text provided as input to bcb {set,test} " " NOTE: any ':' character in <val> will be replaced by line feed " " during 'bcb set' and used as separator by upper layers " ); |