xref: /rk3399_rockchip-uboot/common/android_bootloader.c (revision 271551c99a0abe2ab0b8f61a1f0efbe74d772507)
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 #include <android_bootloader.h>
8 #include <android_bootloader_message.h>
9 
10 #include <cli.h>
11 #include <common.h>
12 #include <malloc.h>
13 
14 #define ANDROID_PARTITION_BOOT "boot"
15 #define ANDROID_PARTITION_SYSTEM "system"
16 
17 #define ANDROID_ARG_SLOT_SUFFIX "androidboot.slot_suffix="
18 #define ANDROID_ARG_ROOT "root="
19 #define ANDROID_ARG_SERIALNO "androidboot.serialno="
20 
21 static int android_bootloader_message_load(
22 	struct blk_desc *dev_desc,
23 	const disk_partition_t *part_info,
24 	struct android_bootloader_message *message)
25 {
26 	ulong message_blocks = sizeof(struct android_bootloader_message) /
27 	    part_info->blksz;
28 	if (message_blocks > part_info->size) {
29 		printf("misc partition too small.\n");
30 		return -1;
31 	}
32 
33 	if (blk_dread(dev_desc, part_info->start, message_blocks, message) !=
34 	    message_blocks) {
35 		printf("Could not read from misc partition\n");
36 		return -1;
37 	}
38 	debug("ANDROID: Loaded BCB, %lu blocks.\n", message_blocks);
39 	return 0;
40 }
41 
42 static int android_bootloader_message_write(
43 	struct blk_desc *dev_desc,
44 	const disk_partition_t *part_info,
45 	struct android_bootloader_message *message)
46 {
47 	ulong message_blocks = sizeof(struct android_bootloader_message) /
48 	    part_info->blksz;
49 	if (message_blocks > part_info->size) {
50 		printf("misc partition too small.\n");
51 		return -1;
52 	}
53 
54 	if (blk_dwrite(dev_desc, part_info->start, message_blocks, message) !=
55 	    message_blocks) {
56 		printf("Could not write to misc partition\n");
57 		return -1;
58 	}
59 	debug("ANDROID: Wrote new BCB, %lu blocks.\n", message_blocks);
60 	return 0;
61 }
62 
63 static enum android_boot_mode android_bootloader_load_and_clear_mode(
64 	struct blk_desc *dev_desc,
65 	const disk_partition_t *misc_part_info)
66 {
67 	struct android_bootloader_message bcb;
68 
69 #ifdef CONFIG_FASTBOOT
70 	char *bootloader_str;
71 
72 	/* Check for message from bootloader stored in RAM from a previous boot.
73 	 */
74 	bootloader_str = (char *)CONFIG_FASTBOOT_BUF_ADDR;
75 	if (!strcmp("reboot-bootloader", bootloader_str)) {
76 		bootloader_str[0] = '\0';
77 		return ANDROID_BOOT_MODE_BOOTLOADER;
78 	}
79 #endif
80 
81 	/* Check and update the BCB message if needed. */
82 	if (android_bootloader_message_load(dev_desc, misc_part_info, &bcb) <
83 	    0) {
84 		printf("WARNING: Unable to load the BCB.\n");
85 		return ANDROID_BOOT_MODE_NORMAL;
86 	}
87 
88 	if (!strcmp("bootonce-bootloader", bcb.command)) {
89 		/* Erase the message in the BCB since this value should be used
90 		 * only once.
91 		 */
92 		memset(bcb.command, 0, sizeof(bcb.command));
93 		android_bootloader_message_write(dev_desc, misc_part_info,
94 						 &bcb);
95 		return ANDROID_BOOT_MODE_BOOTLOADER;
96 	}
97 
98 	if (!strcmp("boot-recovery", bcb.command))
99 		return ANDROID_BOOT_MODE_RECOVERY;
100 
101 	return ANDROID_BOOT_MODE_NORMAL;
102 }
103 
104 /**
105  * Return the reboot reason string for the passed boot mode.
106  *
107  * @param mode	The Android Boot mode.
108  * @return a pointer to the reboot reason string for mode.
109  */
110 static const char *android_boot_mode_str(enum android_boot_mode mode)
111 {
112 	switch (mode) {
113 	case ANDROID_BOOT_MODE_NORMAL:
114 		return "(none)";
115 	case ANDROID_BOOT_MODE_RECOVERY:
116 		return "recovery";
117 	case ANDROID_BOOT_MODE_BOOTLOADER:
118 		return "bootloader";
119 	}
120 	return NULL;
121 }
122 
123 static int android_part_get_info_by_name_suffix(struct blk_desc *dev_desc,
124 						const char *base_name,
125 						const char *slot_suffix,
126 						disk_partition_t *part_info)
127 {
128 	char *part_name;
129 	int part_num;
130 	size_t part_name_len;
131 
132 	part_name_len = strlen(base_name) + 1;
133 	if (slot_suffix)
134 		part_name_len += strlen(slot_suffix);
135 	part_name = malloc(part_name_len);
136 	if (!part_name)
137 		return -1;
138 	strcpy(part_name, base_name);
139 	if (slot_suffix)
140 		strcat(part_name, slot_suffix);
141 
142 	part_num = part_get_info_by_name(dev_desc, part_name, part_info);
143 	if (part_num < 0) {
144 		debug("ANDROID: Could not find partition \"%s\"\n", part_name);
145 		part_num = -1;
146 	}
147 
148 	free(part_name);
149 	return part_num;
150 }
151 
152 static int android_bootloader_boot_bootloader(void)
153 {
154 	const char *fastboot_cmd = env_get("fastbootcmd");
155 
156 	if (fastboot_cmd)
157 		return run_command(fastboot_cmd, CMD_FLAG_ENV);
158 	return -1;
159 }
160 
161 int android_bootloader_boot_kernel(unsigned long kernel_address)
162 {
163 	char kernel_addr_str[12];
164 	char *fdt_addr = env_get("fdt_addr");
165 	char *bootm_args[] = {
166 		"bootm", kernel_addr_str, kernel_addr_str, fdt_addr, NULL };
167 
168 	sprintf(kernel_addr_str, "0x%lx", kernel_address);
169 
170 	printf("Booting kernel at %s with fdt at %s...\n\n\n",
171 	       kernel_addr_str, fdt_addr);
172 	do_bootm(NULL, 0, 4, bootm_args);
173 
174 	return -1;
175 }
176 
177 static char *strjoin(const char **chunks, char separator)
178 {
179 	int len, joined_len = 0;
180 	char *ret, *current;
181 	const char **p;
182 
183 	for (p = chunks; *p; p++)
184 		joined_len += strlen(*p) + 1;
185 
186 	if (!joined_len) {
187 		ret = malloc(1);
188 		if (ret)
189 			ret[0] = '\0';
190 		return ret;
191 	}
192 
193 	ret = malloc(joined_len);
194 	current = ret;
195 	if (!ret)
196 		return ret;
197 
198 	for (p = chunks; *p; p++) {
199 		len = strlen(*p);
200 		memcpy(current, *p, len);
201 		current += len;
202 		*current = separator;
203 		current++;
204 	}
205 	/* Replace the last separator by a \0. */
206 	current[-1] = '\0';
207 	return ret;
208 }
209 
210 /** android_assemble_cmdline - Assemble the command line to pass to the kernel
211  * @return a newly allocated string
212  */
213 char *android_assemble_cmdline(const char *slot_suffix,
214 				      const char *extra_args)
215 {
216 	const char *cmdline_chunks[16];
217 	const char **current_chunk = cmdline_chunks;
218 	char *env_cmdline, *cmdline, *rootdev_input, *serialno;
219 	char *allocated_suffix = NULL;
220 	char *allocated_serialno = NULL;
221 	char *allocated_rootdev = NULL;
222 	unsigned long rootdev_len;
223 
224 	env_cmdline = env_get("bootargs");
225 	if (env_cmdline)
226 		*(current_chunk++) = env_cmdline;
227 
228 	/* The |slot_suffix| needs to be passed to the kernel to know what
229 	 * slot to boot from.
230 	 */
231 	if (slot_suffix) {
232 		allocated_suffix = malloc(strlen(ANDROID_ARG_SLOT_SUFFIX) +
233 					  strlen(slot_suffix));
234 		strcpy(allocated_suffix, ANDROID_ARG_SLOT_SUFFIX);
235 		strcat(allocated_suffix, slot_suffix);
236 		*(current_chunk++) = allocated_suffix;
237 	}
238 
239 	serialno = env_get("serial#");
240 	if (serialno) {
241 		allocated_serialno = malloc(strlen(ANDROID_ARG_SERIALNO) +
242 					  strlen(serialno) + 1);
243 		memset(allocated_serialno, 0, strlen(ANDROID_ARG_SERIALNO) +
244 				strlen(serialno) + 1);
245 		strcpy(allocated_serialno, ANDROID_ARG_SERIALNO);
246 		strcat(allocated_serialno, serialno);
247 		*(current_chunk++) = allocated_serialno;
248 	}
249 
250 	rootdev_input = env_get("android_rootdev");
251 	if (rootdev_input) {
252 		rootdev_len = strlen(ANDROID_ARG_ROOT) + CONFIG_SYS_CBSIZE + 1;
253 		allocated_rootdev = malloc(rootdev_len);
254 		strcpy(allocated_rootdev, ANDROID_ARG_ROOT);
255 		cli_simple_process_macros(rootdev_input,
256 					  allocated_rootdev +
257 					  strlen(ANDROID_ARG_ROOT));
258 		/* Make sure that the string is null-terminated since the
259 		 * previous could not copy to the end of the input string if it
260 		 * is too big.
261 		 */
262 		allocated_rootdev[rootdev_len - 1] = '\0';
263 		*(current_chunk++) = allocated_rootdev;
264 	}
265 
266 	if (extra_args)
267 		*(current_chunk++) = extra_args;
268 
269 	*(current_chunk++) = NULL;
270 	cmdline = strjoin(cmdline_chunks, ' ');
271 	free(allocated_suffix);
272 	free(allocated_rootdev);
273 	return cmdline;
274 }
275 
276 int android_bootloader_boot_flow(struct blk_desc *dev_desc,
277 				 const disk_partition_t *misc_part_info,
278 				 const char *slot,
279 				 unsigned long kernel_address)
280 {
281 	enum android_boot_mode mode;
282 	disk_partition_t boot_part_info;
283 	disk_partition_t system_part_info;
284 	int boot_part_num, system_part_num;
285 	int ret;
286 	char *command_line;
287 	char slot_suffix[3];
288 	const char *mode_cmdline = NULL;
289 
290 	/* Determine the boot mode and clear its value for the next boot if
291 	 * needed.
292 	 */
293 	mode = android_bootloader_load_and_clear_mode(dev_desc, misc_part_info);
294 	printf("ANDROID: reboot reason: \"%s\"\n", android_boot_mode_str(mode));
295 
296 	switch (mode) {
297 	case ANDROID_BOOT_MODE_NORMAL:
298 		/* In normal mode, we load the kernel from "boot" but append
299 		 * "skip_initramfs" to the cmdline to make it ignore the
300 		 * recovery initramfs in the boot partition.
301 		 */
302 		mode_cmdline = "skip_initramfs";
303 		break;
304 	case ANDROID_BOOT_MODE_RECOVERY:
305 		/* In recovery mode we still boot the kernel from "boot" but
306 		 * don't skip the initramfs so it boots to recovery.
307 		 */
308 		break;
309 	case ANDROID_BOOT_MODE_BOOTLOADER:
310 		/* Bootloader mode enters fastboot. If this operation fails we
311 		 * simply return since we can't recover from this situation by
312 		 * switching to another slot.
313 		 */
314 		return android_bootloader_boot_bootloader();
315 	}
316 
317 	slot_suffix[0] = '\0';
318 	if (slot && slot[0]) {
319 		slot_suffix[0] = '_';
320 		slot_suffix[1] = slot[0];
321 		slot_suffix[2] = '\0';
322 	}
323 
324 	/* Load the kernel from the desired "boot" partition. */
325 	boot_part_num =
326 	    android_part_get_info_by_name_suffix(dev_desc,
327 						 ANDROID_PARTITION_BOOT,
328 						 slot_suffix, &boot_part_info);
329 	if (boot_part_num < 0)
330 		return -1;
331 	debug("ANDROID: Loading kernel from \"%s\", partition %d.\n",
332 	      boot_part_info.name, boot_part_num);
333 
334 	system_part_num =
335 	    android_part_get_info_by_name_suffix(dev_desc,
336 						 ANDROID_PARTITION_SYSTEM,
337 						 slot_suffix,
338 						 &system_part_info);
339 	if (system_part_num < 0)
340 		return -1;
341 	debug("ANDROID: Using system image from \"%s\", partition %d.\n",
342 	      system_part_info.name, system_part_num);
343 
344 	ret = android_image_load(dev_desc, &boot_part_info, kernel_address,
345 				 -1UL);
346 	if (ret < 0)
347 		return ret;
348 
349 	/* Set Android root variables. */
350 	env_set_ulong("android_root_devnum", dev_desc->devnum);
351 	env_set_ulong("android_root_partnum", system_part_num);
352 	env_set("android_slotsufix", slot_suffix);
353 
354 	/* Assemble the command line */
355 	command_line = android_assemble_cmdline(slot_suffix, mode_cmdline);
356 	env_set("bootargs", command_line);
357 
358 	debug("ANDROID: bootargs: \"%s\"\n", command_line);
359 
360 	android_bootloader_boot_kernel(kernel_address);
361 
362 	/* TODO: If the kernel doesn't boot mark the selected slot as bad. */
363 	return -1;
364 }
365 
366 int android_avb_boot_flow(char *slot_suffix, unsigned long kernel_address)
367 {
368 	const char *dev_iface = "mmc";
369 	int dev_num = 0;
370 	struct blk_desc *dev_desc;
371 	disk_partition_t boot_part_info;
372 	int ret;
373 	dev_desc = blk_get_dev(dev_iface, dev_num);
374 	if (!dev_desc) {
375 		printf("Could not find %s %d\n", dev_iface, dev_num);
376 		return -1;
377 	}
378 	/* Load the kernel from the desired "boot" partition. */
379 	android_part_get_info_by_name_suffix(dev_desc,
380 					     ANDROID_PARTITION_BOOT,
381 					     slot_suffix, &boot_part_info);
382 	ret = android_image_load(dev_desc, &boot_part_info, kernel_address,
383 				 -1UL);
384 	if (ret < 0)
385 		return ret;
386 	android_bootloader_boot_kernel(kernel_address);
387 
388 	/* TODO: If the kernel doesn't boot mark the selected slot as bad. */
389 	return -1;
390 }
391