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