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