1 /*
2 * Copyright (c) 2020 Grinn
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "bootutil/bootutil_public.h"
8 #include <dfu/mcuboot.h>
9 #include <init.h>
10 #include <shell/shell.h>
11 #include <stdlib.h>
12
13 #include "mcuboot_priv.h"
14
15 struct area_desc {
16 const char *name;
17 unsigned int id;
18 };
19
20 static const struct area_desc areas[] = {
21 {"primary", FLASH_AREA_IMAGE_PRIMARY},
22 #ifdef FLASH_AREA_IMAGE_SECONDARY
23 {"secondary", FLASH_AREA_IMAGE_SECONDARY},
24 #endif
25 };
26
swap_state_magic_str(uint8_t magic)27 static const char *swap_state_magic_str(uint8_t magic)
28 {
29 switch (magic) {
30 case BOOT_MAGIC_GOOD:
31 return "good";
32 case BOOT_MAGIC_BAD:
33 return "bad";
34 case BOOT_MAGIC_UNSET:
35 return "unset";
36 case BOOT_MAGIC_ANY:
37 return "any";
38 case BOOT_MAGIC_NOTGOOD:
39 return "notgood";
40 }
41
42 return "unknown";
43 }
44
swap_type_str(uint8_t type)45 static const char *swap_type_str(uint8_t type)
46 {
47 switch (type) {
48 case BOOT_SWAP_TYPE_NONE:
49 return "none";
50 case BOOT_SWAP_TYPE_TEST:
51 return "test";
52 case BOOT_SWAP_TYPE_PERM:
53 return "perm";
54 case BOOT_SWAP_TYPE_REVERT:
55 return "revert";
56 case BOOT_SWAP_TYPE_FAIL:
57 return "fail";
58 }
59
60 return "unknown";
61 }
62
swap_state_flag_str(uint8_t flag)63 static const char *swap_state_flag_str(uint8_t flag)
64 {
65 switch (flag) {
66 case BOOT_FLAG_SET:
67 return "set";
68 case BOOT_FLAG_BAD:
69 return "bad";
70 case BOOT_FLAG_UNSET:
71 return "unset";
72 case BOOT_FLAG_ANY:
73 return "any";
74 }
75
76 return "unknown";
77 }
78
cmd_mcuboot_erase(const struct shell * shell,size_t argc,char ** argv)79 static int cmd_mcuboot_erase(const struct shell *shell, size_t argc,
80 char **argv)
81 {
82 unsigned int id;
83 int err;
84
85 id = strtoul(argv[1], NULL, 0);
86
87 err = boot_erase_img_bank(id);
88 if (err) {
89 shell_error(shell, "failed to erase bank %u", id);
90 return err;
91 }
92
93 return 0;
94 }
95
cmd_mcuboot_confirm(const struct shell * shell,size_t argc,char ** argv)96 static int cmd_mcuboot_confirm(const struct shell *shell, size_t argc,
97 char **argv)
98 {
99 int err;
100
101 err = boot_write_img_confirmed();
102 if (err) {
103 shell_error(shell, "failed to confirm: %d", err);
104 }
105
106 return err;
107 }
108
cmd_mcuboot_request_upgrade(const struct shell * shell,size_t argc,char ** argv)109 static int cmd_mcuboot_request_upgrade(const struct shell *shell, size_t argc,
110 char **argv)
111 {
112 int permanent = 0;
113 int err;
114
115 if (argc > 1) {
116 if (!strcmp(argv[1], "permanent")) {
117 permanent = 1;
118 } else {
119 shell_warn(shell, "invalid argument!");
120 return -EINVAL;
121 }
122 }
123
124 err = boot_request_upgrade(permanent);
125 if (err) {
126 shell_error(shell, "failed to request upgrade: %d", err);
127 }
128
129 return err;
130 }
131
cmd_mcuboot_info_area(const struct shell * shell,const struct area_desc * area)132 static int cmd_mcuboot_info_area(const struct shell *shell,
133 const struct area_desc *area)
134 {
135 struct mcuboot_img_header hdr;
136 struct boot_swap_state swap_state;
137 int err;
138
139 err = boot_read_bank_header(area->id, &hdr, sizeof(hdr));
140 if (err) {
141 shell_error(shell, "failed to read %s area (%u) %s: %d",
142 area->name, area->id, "header", err);
143 return err;
144 }
145
146 shell_print(shell, "%s area (%u):", area->name, area->id);
147 shell_print(shell, " version: %u.%u.%u+%u",
148 (unsigned int) hdr.h.v1.sem_ver.major,
149 (unsigned int) hdr.h.v1.sem_ver.minor,
150 (unsigned int) hdr.h.v1.sem_ver.revision,
151 (unsigned int) hdr.h.v1.sem_ver.build_num);
152 shell_print(shell, " image size: %u",
153 (unsigned int) hdr.h.v1.image_size);
154
155 err = boot_read_swap_state_by_id(area->id, &swap_state);
156 if (err) {
157 shell_error(shell, "failed to read %s area (%u) %s: %d",
158 area->name, area->id, "swap state", err);
159 return err;
160 }
161
162 shell_print(shell, " magic: %s",
163 swap_state_magic_str(swap_state.magic));
164
165 if (IS_ENABLED(CONFIG_MCUBOOT_TRAILER_SWAP_TYPE)) {
166 shell_print(shell, " swap type: %s",
167 swap_type_str(swap_state.swap_type));
168 }
169
170 shell_print(shell, " copy done: %s",
171 swap_state_flag_str(swap_state.copy_done));
172 shell_print(shell, " image ok: %s",
173 swap_state_flag_str(swap_state.image_ok));
174
175 return 0;
176 }
177
cmd_mcuboot_info(const struct shell * shell,size_t argc,char ** argv)178 static int cmd_mcuboot_info(const struct shell *shell, size_t argc,
179 char **argv)
180 {
181 int i;
182
183 shell_print(shell, "swap type: %s", swap_type_str(mcuboot_swap_type()));
184 shell_print(shell, "confirmed: %d", boot_is_img_confirmed());
185
186 for (i = 0; i < ARRAY_SIZE(areas); i++) {
187 shell_print(shell, "");
188 cmd_mcuboot_info_area(shell, &areas[i]);
189 }
190
191 return 0;
192 }
193
194 SHELL_STATIC_SUBCMD_SET_CREATE(mcuboot_cmds,
195 SHELL_CMD_ARG(confirm, NULL, "confirm", cmd_mcuboot_confirm, 1, 0),
196 SHELL_CMD_ARG(erase, NULL, "erase <area_id>", cmd_mcuboot_erase, 2, 0),
197 SHELL_CMD_ARG(request_upgrade, NULL, "request_upgrade [permanent]",
198 cmd_mcuboot_request_upgrade, 1, 1),
199 SHELL_SUBCMD_SET_END /* Array terminated. */
200 );
201
202 SHELL_CMD_REGISTER(mcuboot, &mcuboot_cmds, "MCUboot commands",
203 cmd_mcuboot_info);
204