blob: 1a376f3302ba3c516518c6ff034aef8df856d1b5 [file] [log] [blame]
Xindong Xue5d4d172023-04-10 10:30:25 +08001// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2/*
3 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
4 */
5
6#include <common.h>
7#include <command.h>
8#include <env.h>
9#include <malloc.h>
10#ifdef CONFIG_AML_MTD
11#include <linux/mtd/mtd.h>
12#endif
13#include <asm/byteorder.h>
14#include <config.h>
15#include <asm/amlogic/arch/io.h>
16#include <amlogic/partition_table.h>
17#include <amlogic/libavb/libavb.h>
18#include <version.h>
19#ifdef CONFIG_UNIFY_BOOTLOADER
20#include "cmd_bootctl_wrapper.h"
21#endif
22#include "cmd_bootctl_utils.h"
23
24//extern int nand_store_write(const char *name, loff_t off, size_t size, void *buf);
25
26#ifdef CONFIG_BOOTLOADER_CONTROL_BLOCK
27#define COMMANDBUF_SIZE 32
28#define STATUSBUF_SIZE 32
29#define RECOVERYBUF_SIZE 768
30
31#define BOOTINFO_OFFSET 864
32#define SLOTBUF_SIZE 32
33#define MISCBUF_SIZE 1088
34
35struct bootloader_message {
36 char command[32];
37 char status[32];
38 char recovery[768];
39 // The 'recovery' field used to be 1024 bytes. It has only ever
40 // been used to store the recovery command line, so 768 bytes
41 // should be plenty. We carve off the last 256 bytes to store the
42 // stage string (for multistage packages) and possible future
43 // expansion.
44 char stage[32];
45 char slot_suffix[32];
46 char reserved[192];
47};
48
49typedef struct BrilloSlotInfo {
50 u8 bootable;
51 u8 online;
52 u8 reserved[2];
53} BrilloSlotInfo;
54
55typedef struct BrilloBootInfo {
56 // Used by fs_mgr. Must be NUL terminated.
57 char bootctrl_suffix[4];
58
59 // Magic for identification - must be 'B', 'C', 'c' (short for
60 // "boot_control copy" implementation).
61 u8 magic[3];
62
63 // Version of BrilloBootInfo struct, must be 0 or larger.
64 u8 version;
65
66 // Currently active slot.
67 u8 active_slot;
68
69 // Information about each slot.
70 BrilloSlotInfo slot_info[2];
71 u8 attemp_times;
72
73 u8 reserved[14];
74} BrilloBootInfo;
75
76#if (IS_ENABLED(CONFIG_UNIFY_BOOTLOADER))
77bootctl_func_handles cmd_bootctrl_handles = {0};
78#endif
79
80bool boot_info_validate(BrilloBootInfo *info)
81{
82 if (info->magic[0] != 'B' || info->magic[1] != 'C' ||
83 info->magic[2] != 'c')
84 return false;
85 if (info->active_slot >= 2)
86 return false;
87 return true;
88}
89
90static void boot_info_reset(BrilloBootInfo *info)
91{
92 memset(info, '\0', SLOTBUF_SIZE);
93 info->magic[0] = 'B';
94 info->magic[1] = 'C';
95 info->magic[2] = 'c';
96 info->active_slot = 0;
97 info->slot_info[0].bootable = 1;
98 info->slot_info[0].online = 1;
99 info->slot_info[1].bootable = 0;
100 info->slot_info[1].online = 0;
101 info->attemp_times = 0;
102 memcpy(info->bootctrl_suffix, "_a", 2);
103}
104
105void dump_boot_info(BrilloBootInfo *info)
106{
107 pr_info("info->attemp_times = %u\n", info->attemp_times);
108 pr_info("info->active_slot = %u\n", info->active_slot);
109 pr_info("info->slot_info[0].bootable = %u\n", info->slot_info[0].bootable);
110 pr_info("info->slot_info[0].online = %u\n", info->slot_info[0].online);
111 pr_info("info->slot_info[1].bootable = %u\n", info->slot_info[1].bootable);
112 pr_info("info->slot_info[1].online = %u\n", info->slot_info[1].online);
113 pr_info("info->attemp_times = %u\n", info->attemp_times);
114}
115
116int boot_info_get_attemp_times(BrilloBootInfo *info)
117{
118 return info->attemp_times;
119}
120
121int boot_info_change_online_slot(BrilloBootInfo *info)
122{
123 BrilloSlotInfo tmp_info;
124
125 memcpy(&tmp_info, &info->slot_info[0], sizeof(BrilloSlotInfo));
126 memcpy(&info->slot_info[0], &info->slot_info[1], sizeof(BrilloSlotInfo));
127 memcpy(&info->slot_info[1], &tmp_info, sizeof(BrilloSlotInfo));
128 info->attemp_times = 0;
129 return 0;
130}
131
132int boot_info_get_online_slot(BrilloBootInfo *info)
133{
134 if (info->slot_info[0].online == 1)
135 return 0;
136
137 if (info->slot_info[1].online == 1)
138 return 1;
139
140 return 0;
141}
142
143int boot_info_set_active_slot(BrilloBootInfo *info, int slot)
144{
145 if (slot == 0) {
146 info->active_slot = 0;
147 info->slot_info[0].bootable = 1;
148 info->slot_info[0].online = 1;
149 info->slot_info[1].bootable = 0;
150 info->slot_info[1].online = 0;
151 info->attemp_times = 0;
152 memcpy(info->bootctrl_suffix, "_a", 2);
153 } else {
154 info->active_slot = 1;
155 info->slot_info[0].bootable = 0;
156 info->slot_info[0].online = 0;
157 info->slot_info[1].bootable = 1;
158 info->slot_info[1].online = 1;
159 info->attemp_times = 0;
160 memcpy(info->bootctrl_suffix, "_b", 2);
161 }
162
163 dump_boot_info(info);
164
165 return 0;
166}
167
168bool boot_info_load(BrilloBootInfo *out_info, char *miscbuf)
169{
170 memcpy(out_info, miscbuf + BOOTINFO_OFFSET, SLOTBUF_SIZE);
171 dump_boot_info(out_info);
172 return true;
173}
174
175bool boot_info_save(BrilloBootInfo *info, char *miscbuf)
176{
177 char *partition = "misc";
178
179 printf("save boot-info\n");
180 memcpy(miscbuf + BOOTINFO_OFFSET, info, SLOTBUF_SIZE);
181 dump_boot_info(info);
182#ifdef CONFIG_AML_MTD
183 enum boot_type_e device_boot_flag = store_get_type();
184
185 if (device_boot_flag == BOOT_NAND_NFTL || device_boot_flag == BOOT_NAND_MTD ||
186 device_boot_flag == BOOT_SNAND) {
187 int ret = 0;
188
189 ret = run_command("store erase misc 0 0x4000", 0);
190 if (ret != 0) {
191 printf("erase partition misc failed!\n");
192 return false;
193 }
194 }
195#endif
196
197 store_write((const char *)partition, 0, MISCBUF_SIZE, (unsigned char *)miscbuf);
198
199 return true;
200}
201
202static int do_GetValidSlot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
203{
204 char miscbuf[4096] = {0};
205 BrilloBootInfo info;
206 int attemp_times;
207 int slot;
208 int ret = 0;
209
210 if (argc != 1)
211 return cmd_usage(cmdtp);
212
213 ret = boot_info_open_partition(miscbuf);
214 if (ret != 0)
215 return -1;
216
217 boot_info_load(&info, miscbuf);
218
219#ifndef CONFIG_AB_SYSTEM
220 char command[32];
221
222 memcpy(command, miscbuf, 32);
223 if (!memcmp(command, "boot-recovery", strlen("boot-recovery"))) {
224 run_command("run init_display", 0);
225 run_command("run storeargs", 0);
226 if (run_command("run recovery_from_flash", 0) < 0) {
227 printf("run_command for cmd:run recovery_from_flash failed.\n");
228 return -1;
229 }
230 printf("run command:run recovery_from_flash successful.\n");
231 return 0;
232 }
233#endif
234
235 if (!boot_info_validate(&info)) {
236 pr_info("boot-info is invalid. Resetting.\n");
237 boot_info_reset(&info);
238 boot_info_save(&info, miscbuf);
239 }
240
241 attemp_times = boot_info_get_attemp_times(&info);
242 pr_info("attemp_times = %d\n", attemp_times);
243
244 if (attemp_times == -1)
245 boot_info_change_online_slot(&info);
246
247 //slot = boot_info_get_online_slot(&info);
248 slot = info.active_slot;
249 pr_info("active slot = %d\n", slot);
250
251#ifdef CONFIG_AML_MTD
252 //check if boot_a/b on nand
253 enum boot_type_e device_boot_flag = store_get_type();
254
255 if (device_boot_flag == BOOT_NAND_MTD) {
256 struct mtd_info *nand;
257
258 nand = get_mtd_device_nm("boot_a");
259 if (!IS_ERR(nand))
260 has_boot_slot = 1;
261 else
262 has_boot_slot = 0;
263 }
264#endif
265
266 if (slot == 0) {
267 if (has_boot_slot == 1) {
268 env_set("active_slot", "_a");
269 env_set("boot_part", "boot_a");
270 env_set("recovery_part", "recovery_a");
271 env_set("slot-suffixes", "0");
272 } else {
273 env_set("active_slot", "normal");
274 env_set("boot_part", "boot");
275 env_set("recovery_part", "recovery");
276 env_set("slot-suffixes", "-1");
277 }
278 } else {
279 if (has_boot_slot == 1) {
280 env_set("active_slot", "_b");
281 env_set("boot_part", "boot_b");
282 env_set("recovery_part", "recovery_b");
283 env_set("slot-suffixes", "1");
284 } else {
285 env_set("active_slot", "normal");
286 env_set("boot_part", "boot");
287 env_set("recovery_part", "recovery");
288 env_set("slot-suffixes", "-1");
289 }
290 }
291
292 if (dynamic_partition)
293 env_set("partition_mode", "dynamic");
294 else
295 env_set("partition_mode", "normal");
296
297 return 0;
298}
299
300static int do_SetActiveSlot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
301{
302 char miscbuf[4096] = {0};
303 BrilloBootInfo info;
304 int ret = 0;
305
306 if (argc != 2)
307 return cmd_usage(cmdtp);
308
309 if (has_boot_slot == 0) {
310 pr_info("device is not ab mode\n");
311 return -1;
312 }
313
314 ret = boot_info_open_partition(miscbuf);
315 if (ret != 0)
316 return -1;
317
318 boot_info_load(&info, miscbuf);
319
320 if (!boot_info_validate(&info)) {
321 pr_info("boot-info is invalid. Resetting.\n");
322 boot_info_reset(&info);
323 boot_info_save(&info, miscbuf);
324 }
325
326 if (strcmp(argv[1], "a") == 0) {
327 env_set("active_slot", "_a");
328 env_set("boot_part", "boot_a");
329 env_set("recovery_part", "recovery_a");
330 env_set("slot-suffixes", "0");
331 pr_info("set active slot a\n");
332 boot_info_set_active_slot(&info, 0);
333 } else if (strcmp(argv[1], "b") == 0) {
334 env_set("active_slot", "_b");
335 env_set("boot_part", "boot_b");
336 env_set("recovery_part", "recovery_b");
337 env_set("slot-suffixes", "1");
338 pr_info("set active slot b\n");
339 boot_info_set_active_slot(&info, 1);
340 } else {
341 pr_info("error input slot\n");
342 return -1;
343 }
344
345 boot_info_save(&info, miscbuf);
346
347 return 0;
348}
349
350static int do_GetSystemMode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
351{
352#ifdef CONFIG_SYSTEM_AS_ROOT
353 env_set("system_mode", "1");
354#else
355 env_set("system_mode", "0");
356#endif
357
358 return 0;
359}
360
361static int do_GetAvbMode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
362{
363 env_set("avb2", "0");
364
365 return 0;
366}
367
368#endif /* CONFIG_BOOTLOADER_CONTROL_BLOCK */
369
370#ifdef CONFIG_UNIFY_BOOTLOADER
371bootctl_func_handles *get_bootctl_cmd_func(void)
372{
373 cmd_bootctrl_handles.do_GetValidSlot_func = do_GetValidSlot;
374 cmd_bootctrl_handles.do_SetActiveSlot_func = do_SetActiveSlot;
375 cmd_bootctrl_handles.do_GetSystemMode_func = do_GetSystemMode;
376 cmd_bootctrl_handles.do_GetAvbMode_func = do_GetAvbMode;
377
378 return &cmd_bootctrl_handles;
379}
380#else
381U_BOOT_CMD
382(get_valid_slot, 2, 0, do_GetValidSlot,
383"get_valid_slot",
384"\nThis command will choose valid slot to boot up which saved in misc\n"
385"partition by mark to decide whether execute command!\n"
386"So you can execute command: get_valid_slot"
387);
388
389U_BOOT_CMD
390(set_active_slot, 2, 1, do_SetActiveSlot,
391"set_active_slot",
392"\nThis command will set active slot\n"
393"So you can execute command: set_active_slot a"
394);
395
396U_BOOT_CMD
397(get_system_as_root_mode, 1, 0, do_GetSystemMode,
398"get_system_as_root_mode",
399"\nThis command will get system_as_root_mode\n"
400"So you can execute command: get_system_as_root_mode"
401);
402
403U_BOOT_CMD
404(get_avb_mode, 1, 0, do_GetAvbMode,
405"get_avb_mode",
406"\nThis command will get avb mode\n"
407"So you can execute command: get_avb_mode"
408);
409#endif
410