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