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