blob: 6e8d3e615db0d0f2d83b5a07a0dc351ecf7464d3 [file] [log] [blame]
Mattijs Korpershoek125d9f32024-07-10 10:40:05 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Bootmeth for Android
4 *
5 * Copyright (C) 2024 BayLibre, SAS
6 * Written by Mattijs Korpershoek <mkorpershoek@baylibre.com>
7 */
8#define LOG_CATEGORY UCLASS_BOOTSTD
9
10#include <android_ab.h>
11#include <android_image.h>
12#if CONFIG_IS_ENABLED(AVB_VERIFY)
13#include <avb_verify.h>
14#endif
15#include <bcb.h>
16#include <blk.h>
17#include <bootflow.h>
18#include <bootm.h>
19#include <bootmeth.h>
20#include <dm.h>
21#include <image.h>
22#include <malloc.h>
23#include <mapmem.h>
24#include <part.h>
25#include "bootmeth_android.h"
26
27#define BCB_FIELD_COMMAND_SZ 32
28#define BCB_PART_NAME "misc"
29#define BOOT_PART_NAME "boot"
30#define VENDOR_BOOT_PART_NAME "vendor_boot"
31
32/**
33 * struct android_priv - Private data
34 *
35 * This is read from the disk and recorded for use when the full Android
36 * kernel must be loaded and booted
37 *
38 * @boot_mode: Requested boot mode (normal, recovery, bootloader)
39 * @slot: Nul-terminated partition slot suffix read from BCB ("a\0" or "b\0")
40 * @header_version: Android boot image header version
41 */
42struct android_priv {
43 enum android_boot_mode boot_mode;
44 char slot[2];
45 u32 header_version;
46};
47
48static int android_check(struct udevice *dev, struct bootflow_iter *iter)
49{
50 /* This only works on mmc devices */
51 if (bootflow_iter_check_mmc(iter))
52 return log_msg_ret("mmc", -ENOTSUPP);
53
54 /*
55 * This only works on whole devices, as multiple
56 * partitions are needed to boot Android
57 */
58 if (iter->part != 0)
59 return log_msg_ret("mmc part", -ENOTSUPP);
60
61 return 0;
62}
63
64static int scan_boot_part(struct udevice *blk, struct android_priv *priv)
65{
66 struct blk_desc *desc = dev_get_uclass_plat(blk);
67 struct disk_partition partition;
68 char partname[PART_NAME_LEN];
69 ulong num_blks, bufsz;
70 char *buf;
71 int ret;
72
73 sprintf(partname, BOOT_PART_NAME "_%s", priv->slot);
74 ret = part_get_info_by_name(desc, partname, &partition);
75 if (ret < 0)
76 return log_msg_ret("part info", ret);
77
78 num_blks = DIV_ROUND_UP(sizeof(struct andr_boot_img_hdr_v0), desc->blksz);
79 bufsz = num_blks * desc->blksz;
80 buf = malloc(bufsz);
81 if (!buf)
82 return log_msg_ret("buf", -ENOMEM);
83
84 ret = blk_read(blk, partition.start, num_blks, buf);
85 if (ret != num_blks) {
86 free(buf);
87 return log_msg_ret("part read", -EIO);
88 }
89
90 if (!is_android_boot_image_header(buf)) {
91 free(buf);
92 return log_msg_ret("header", -ENOENT);
93 }
94
95 priv->header_version = ((struct andr_boot_img_hdr_v0 *)buf)->header_version;
96 free(buf);
97
98 return 0;
99}
100
101static int scan_vendor_boot_part(struct udevice *blk, struct android_priv *priv)
102{
103 struct blk_desc *desc = dev_get_uclass_plat(blk);
104 struct disk_partition partition;
105 char partname[PART_NAME_LEN];
106 ulong num_blks, bufsz;
107 char *buf;
108 int ret;
109
110 sprintf(partname, VENDOR_BOOT_PART_NAME "_%s", priv->slot);
111 ret = part_get_info_by_name(desc, partname, &partition);
112 if (ret < 0)
113 return log_msg_ret("part info", ret);
114
115 num_blks = DIV_ROUND_UP(sizeof(struct andr_vnd_boot_img_hdr), desc->blksz);
116 bufsz = num_blks * desc->blksz;
117 buf = malloc(bufsz);
118 if (!buf)
119 return log_msg_ret("buf", -ENOMEM);
120
121 ret = blk_read(blk, partition.start, num_blks, buf);
122 if (ret != num_blks) {
123 free(buf);
124 return log_msg_ret("part read", -EIO);
125 }
126
127 if (!is_android_vendor_boot_image_header(buf)) {
128 free(buf);
129 return log_msg_ret("header", -ENOENT);
130 }
131 free(buf);
132
133 return 0;
134}
135
136static int android_read_slot_from_bcb(struct bootflow *bflow, bool decrement)
137{
138 struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
139 struct android_priv *priv = bflow->bootmeth_priv;
140 struct disk_partition misc;
141 char slot_suffix[3];
142 int ret;
143
144 ret = part_get_info_by_name(desc, BCB_PART_NAME, &misc);
145 if (ret < 0)
146 return log_msg_ret("part", ret);
147
148 ret = ab_select_slot(desc, &misc, decrement);
149 if (ret < 0)
150 return log_msg_ret("slot", ret);
151
152 priv->slot[0] = BOOT_SLOT_NAME(ret);
153 priv->slot[1] = '\0';
154
155 sprintf(slot_suffix, "_%s", priv->slot);
156 ret = bootflow_cmdline_set_arg(bflow, "androidboot.slot_suffix",
157 slot_suffix, false);
158 if (ret < 0)
159 return log_msg_ret("cmdl", ret);
160
161 return 0;
162}
163
164static int configure_serialno(struct bootflow *bflow)
165{
166 char *serialno = env_get("serial#");
167
168 if (!serialno)
169 return log_msg_ret("serial", -ENOENT);
170
171 return bootflow_cmdline_set_arg(bflow, "androidboot.serialno", serialno, false);
172}
173
174static int android_read_bootflow(struct udevice *dev, struct bootflow *bflow)
175{
176 struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
177 struct disk_partition misc;
178 struct android_priv *priv;
179 char command[BCB_FIELD_COMMAND_SZ];
180 int ret;
181
182 bflow->state = BOOTFLOWST_MEDIA;
183
184 /*
185 * bcb_find_partition_and_load() will print errors to stdout
186 * if BCB_PART_NAME is not found. To avoid that, check if the
187 * partition exists first.
188 */
189 ret = part_get_info_by_name(desc, BCB_PART_NAME, &misc);
190 if (ret < 0)
191 return log_msg_ret("part", ret);
192
193 ret = bcb_find_partition_and_load("mmc", desc->devnum, BCB_PART_NAME);
194 if (ret < 0)
195 return log_msg_ret("bcb load", ret);
196
197 ret = bcb_get(BCB_FIELD_COMMAND, command, sizeof(command));
198 if (ret < 0)
199 return log_msg_ret("bcb read", ret);
200
201 priv = malloc(sizeof(struct android_priv));
202 if (!priv)
203 return log_msg_ret("buf", -ENOMEM);
204
205 if (!strcmp("bootonce-bootloader", command)) {
206 priv->boot_mode = ANDROID_BOOT_MODE_BOOTLOADER;
207 bflow->os_name = strdup("Android (bootloader)");
208 } else if (!strcmp("boot-fastboot", command)) {
209 priv->boot_mode = ANDROID_BOOT_MODE_RECOVERY;
210 bflow->os_name = strdup("Android (fastbootd)");
211 } else if (!strcmp("boot-recovery", command)) {
212 priv->boot_mode = ANDROID_BOOT_MODE_RECOVERY;
213 bflow->os_name = strdup("Android (recovery)");
214 } else {
215 priv->boot_mode = ANDROID_BOOT_MODE_NORMAL;
216 bflow->os_name = strdup("Android");
217 }
218 if (!bflow->os_name)
219 return log_msg_ret("os", -ENOMEM);
220
221 if (priv->boot_mode == ANDROID_BOOT_MODE_BOOTLOADER) {
222 /* Clear BCB */
223 memset(command, 0, sizeof(command));
224 ret = bcb_set(BCB_FIELD_COMMAND, command);
225 if (ret < 0) {
226 free(priv);
227 return log_msg_ret("bcb set", ret);
228 }
229 ret = bcb_store();
230 if (ret < 0) {
231 free(priv);
232 return log_msg_ret("bcb store", ret);
233 }
234
235 bflow->bootmeth_priv = priv;
236 bflow->state = BOOTFLOWST_READY;
237 return 0;
238 }
239
240 bflow->bootmeth_priv = priv;
241
242 /* For recovery and normal boot, we need to scan the partitions */
243 ret = android_read_slot_from_bcb(bflow, false);
244 if (ret < 0) {
245 log_err("read slot: %d", ret);
246 goto free_priv;
247 }
248
249 ret = scan_boot_part(bflow->blk, priv);
250 if (ret < 0) {
251 log_debug("scan boot failed: err=%d\n", ret);
252 goto free_priv;
253 }
254
255 if (priv->header_version != 4) {
256 log_debug("only boot.img v4 is supported %u\n", priv->header_version);
257 ret = -EINVAL;
258 goto free_priv;
259 }
260
261 ret = scan_vendor_boot_part(bflow->blk, priv);
262 if (ret < 0) {
263 log_debug("scan vendor_boot failed: err=%d\n", ret);
264 goto free_priv;
265 }
266
267 /* Ignoring return code: setting serial number is not mandatory for booting */
268 configure_serialno(bflow);
269
270 if (priv->boot_mode == ANDROID_BOOT_MODE_NORMAL) {
271 ret = bootflow_cmdline_set_arg(bflow, "androidboot.force_normal_boot",
272 "1", false);
273 if (ret < 0) {
274 log_debug("normal_boot %d", ret);
275 goto free_priv;
276 }
277 }
278
279 bflow->state = BOOTFLOWST_READY;
280
281 return 0;
282
283 free_priv:
284 free(priv);
285 bflow->bootmeth_priv = NULL;
286 return ret;
287}
288
289static int android_read_file(struct udevice *dev, struct bootflow *bflow,
290 const char *file_path, ulong addr, ulong *sizep)
291{
292 /*
293 * Reading individual files is not supported since we only
294 * operate on whole mmc devices (because we require multiple partitions)
295 */
296 return log_msg_ret("Unsupported", -ENOSYS);
297}
298
299/**
300 * read_slotted_partition() - Read a partition by appending a slot suffix
301 *
302 * Most modern Android devices use Seamless Updates, where each partition
303 * is duplicated. For example, the boot partition has boot_a and boot_b.
304 * For more information, see:
305 * https://source.android.com/docs/core/ota/ab
306 * https://source.android.com/docs/core/ota/ab/ab_implement
307 *
308 * @blk: Block device to read
309 * @name: Partition name to read
310 * @slot: Nul-terminated slot suffixed to partition name ("a\0" or "b\0")
311 * @addr: Address where the partition content is loaded into
312 * Return: 0 if OK, negative errno on failure.
313 */
314static int read_slotted_partition(struct blk_desc *desc, const char *const name,
315 const char slot[2], ulong addr)
316{
317 struct disk_partition partition;
318 char partname[PART_NAME_LEN];
319 int ret;
320 u32 n;
321
322 /* Ensure name fits in partname it should be: <name>_<slot>\0 */
323 if (strlen(name) > (PART_NAME_LEN - 2 - 1))
324 return log_msg_ret("name too long", -EINVAL);
325
326 sprintf(partname, "%s_%s", name, slot);
327 ret = part_get_info_by_name(desc, partname, &partition);
328 if (ret < 0)
329 return log_msg_ret("part", ret);
330
331 n = blk_dread(desc, partition.start, partition.size, map_sysmem(addr, 0));
332 if (n < partition.size)
333 return log_msg_ret("part read", -EIO);
334
335 return 0;
336}
337
338#if CONFIG_IS_ENABLED(AVB_VERIFY)
339static int avb_append_commandline_arg(struct bootflow *bflow, char *arg)
340{
341 char *key = strsep(&arg, "=");
342 char *value = arg;
343 int ret;
344
345 ret = bootflow_cmdline_set_arg(bflow, key, value, false);
346 if (ret < 0)
347 return log_msg_ret("avb cmdline", ret);
348
349 return 0;
350}
351
352static int avb_append_commandline(struct bootflow *bflow, char *cmdline)
353{
354 char *arg = strsep(&cmdline, " ");
355 int ret;
356
357 while (arg) {
358 ret = avb_append_commandline_arg(bflow, arg);
359 if (ret < 0)
360 return ret;
361
362 arg = strsep(&cmdline, " ");
363 }
364
365 return 0;
366}
367
368static int run_avb_verification(struct bootflow *bflow)
369{
370 struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
371 struct android_priv *priv = bflow->bootmeth_priv;
372 const char * const requested_partitions[] = {"boot", "vendor_boot"};
373 struct AvbOps *avb_ops;
374 AvbSlotVerifyResult result;
375 AvbSlotVerifyData *out_data;
376 enum avb_boot_state boot_state;
377 char *extra_args;
378 char slot_suffix[3];
379 bool unlocked = false;
380 int ret;
381
382 avb_ops = avb_ops_alloc(desc->devnum);
383 if (!avb_ops)
384 return log_msg_ret("avb ops", -ENOMEM);
385
386 sprintf(slot_suffix, "_%s", priv->slot);
387
388 ret = avb_ops->read_is_device_unlocked(avb_ops, &unlocked);
389 if (ret != AVB_IO_RESULT_OK)
390 return log_msg_ret("avb lock", -EIO);
391
392 result = avb_slot_verify(avb_ops,
393 requested_partitions,
394 slot_suffix,
395 unlocked,
396 AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
397 &out_data);
398
399 if (result != AVB_SLOT_VERIFY_RESULT_OK) {
400 printf("Verification failed, reason: %s\n",
401 str_avb_slot_error(result));
402 avb_slot_verify_data_free(out_data);
403 return log_msg_ret("avb verify", -EIO);
404 }
405
406 if (unlocked)
407 boot_state = AVB_ORANGE;
408 else
409 boot_state = AVB_GREEN;
410
411 extra_args = avb_set_state(avb_ops, boot_state);
412 if (extra_args) {
413 /* extra_args will be modified after this. This is fine */
414 ret = avb_append_commandline_arg(bflow, extra_args);
415 if (ret < 0)
416 goto free_out_data;
417 }
418
419 ret = avb_append_commandline(bflow, out_data->cmdline);
420 if (ret < 0)
421 goto free_out_data;
422
423 return 0;
424
425 free_out_data:
426 if (out_data)
427 avb_slot_verify_data_free(out_data);
428
429 return log_msg_ret("avb cmdline", ret);
430}
431#else
432static int run_avb_verification(struct bootflow *bflow)
433{
434 int ret;
435
436 /* When AVB is unsupported, pass ORANGE state */
437 ret = bootflow_cmdline_set_arg(bflow,
438 "androidboot.verifiedbootstate",
439 "orange", false);
440 if (ret < 0)
441 return log_msg_ret("avb cmdline", ret);
442
443 return 0;
444}
445#endif /* AVB_VERIFY */
446
447static int boot_android_normal(struct bootflow *bflow)
448{
449 struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
450 struct android_priv *priv = bflow->bootmeth_priv;
451 int ret;
452 ulong loadaddr = env_get_hex("loadaddr", 0);
453 ulong vloadaddr = env_get_hex("vendor_boot_comp_addr_r", 0);
454
455 ret = run_avb_verification(bflow);
456 if (ret < 0)
457 return log_msg_ret("avb", ret);
458
459 /* Read slot once more to decrement counter from BCB */
460 ret = android_read_slot_from_bcb(bflow, true);
461 if (ret < 0)
462 return log_msg_ret("read slot", ret);
463
464 ret = read_slotted_partition(desc, "boot", priv->slot, loadaddr);
465 if (ret < 0)
466 return log_msg_ret("read boot", ret);
467
468 ret = read_slotted_partition(desc, "vendor_boot", priv->slot, vloadaddr);
469 if (ret < 0)
470 return log_msg_ret("read vendor_boot", ret);
471
472 set_abootimg_addr(loadaddr);
473 set_avendor_bootimg_addr(vloadaddr);
474
475 ret = bootm_boot_start(loadaddr, bflow->cmdline);
476
477 return log_msg_ret("boot", ret);
478}
479
480static int boot_android_recovery(struct bootflow *bflow)
481{
482 int ret;
483
484 ret = boot_android_normal(bflow);
485
486 return log_msg_ret("boot", ret);
487}
488
489static int boot_android_bootloader(struct bootflow *bflow)
490{
491 int ret;
492
493 ret = run_command("fastboot usb 0", 0);
494 do_reset(NULL, 0, 0, NULL);
495
496 return log_msg_ret("boot", ret);
497}
498
499static int android_boot(struct udevice *dev, struct bootflow *bflow)
500{
501 struct android_priv *priv = bflow->bootmeth_priv;
502 int ret;
503
504 switch (priv->boot_mode) {
505 case ANDROID_BOOT_MODE_NORMAL:
506 ret = boot_android_normal(bflow);
507 break;
508 case ANDROID_BOOT_MODE_RECOVERY:
509 ret = boot_android_recovery(bflow);
510 break;
511 case ANDROID_BOOT_MODE_BOOTLOADER:
512 ret = boot_android_bootloader(bflow);
513 break;
514 default:
515 printf("ANDROID: Unknown boot mode %d. Running fastboot...\n",
516 priv->boot_mode);
517 boot_android_bootloader(bflow);
518 /* Tell we failed to boot since boot mode is unknown */
519 ret = -EFAULT;
520 }
521
522 return ret;
523}
524
525static int android_bootmeth_bind(struct udevice *dev)
526{
527 struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
528
529 plat->desc = "Android boot";
530 plat->flags = BOOTMETHF_ANY_PART;
531
532 return 0;
533}
534
535static struct bootmeth_ops android_bootmeth_ops = {
536 .check = android_check,
537 .read_bootflow = android_read_bootflow,
538 .read_file = android_read_file,
539 .boot = android_boot,
540};
541
542static const struct udevice_id android_bootmeth_ids[] = {
543 { .compatible = "u-boot,android" },
544 { }
545};
546
547U_BOOT_DRIVER(bootmeth_android) = {
548 .name = "bootmeth_android",
549 .id = UCLASS_BOOTMETH,
550 .of_match = android_bootmeth_ids,
551 .ops = &android_bootmeth_ops,
552 .bind = android_bootmeth_bind,
553};