blob: 3a5144aaa3b0125cf13ff1805b05e87385263308 [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;
Julien Massonb238dee2024-11-21 11:59:55 +010048 u32 boot_img_size;
49 u32 vendor_boot_img_size;
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +020050};
51
52static int android_check(struct udevice *dev, struct bootflow_iter *iter)
53{
54 /* This only works on mmc devices */
55 if (bootflow_iter_check_mmc(iter))
56 return log_msg_ret("mmc", -ENOTSUPP);
57
58 /*
59 * This only works on whole devices, as multiple
60 * partitions are needed to boot Android
61 */
62 if (iter->part != 0)
63 return log_msg_ret("mmc part", -ENOTSUPP);
64
65 return 0;
66}
67
68static int scan_boot_part(struct udevice *blk, struct android_priv *priv)
69{
70 struct blk_desc *desc = dev_get_uclass_plat(blk);
71 struct disk_partition partition;
72 char partname[PART_NAME_LEN];
73 ulong num_blks, bufsz;
74 char *buf;
75 int ret;
76
Guillaume La Roquedf9e6412024-11-26 09:06:10 +010077 if (priv->slot)
78 sprintf(partname, BOOT_PART_NAME "_%s", priv->slot);
79 else
80 sprintf(partname, BOOT_PART_NAME);
81
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +020082 ret = part_get_info_by_name(desc, partname, &partition);
83 if (ret < 0)
84 return log_msg_ret("part info", ret);
85
86 num_blks = DIV_ROUND_UP(sizeof(struct andr_boot_img_hdr_v0), desc->blksz);
87 bufsz = num_blks * desc->blksz;
88 buf = malloc(bufsz);
89 if (!buf)
90 return log_msg_ret("buf", -ENOMEM);
91
92 ret = blk_read(blk, partition.start, num_blks, buf);
93 if (ret != num_blks) {
94 free(buf);
95 return log_msg_ret("part read", -EIO);
96 }
97
98 if (!is_android_boot_image_header(buf)) {
99 free(buf);
100 return log_msg_ret("header", -ENOENT);
101 }
102
Julien Massonb238dee2024-11-21 11:59:55 +0100103 if (!android_image_get_bootimg_size(buf, &priv->boot_img_size)) {
104 free(buf);
105 return log_msg_ret("get bootimg size", -EINVAL);
106 }
107
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200108 priv->header_version = ((struct andr_boot_img_hdr_v0 *)buf)->header_version;
Julien Massonb238dee2024-11-21 11:59:55 +0100109
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200110 free(buf);
111
112 return 0;
113}
114
115static int scan_vendor_boot_part(struct udevice *blk, struct android_priv *priv)
116{
117 struct blk_desc *desc = dev_get_uclass_plat(blk);
118 struct disk_partition partition;
119 char partname[PART_NAME_LEN];
120 ulong num_blks, bufsz;
121 char *buf;
122 int ret;
123
Guillaume La Roquedf9e6412024-11-26 09:06:10 +0100124 if (priv->slot)
125 sprintf(partname, VENDOR_BOOT_PART_NAME "_%s", priv->slot);
126 else
127 sprintf(partname, VENDOR_BOOT_PART_NAME);
128
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200129 ret = part_get_info_by_name(desc, partname, &partition);
130 if (ret < 0)
131 return log_msg_ret("part info", ret);
132
133 num_blks = DIV_ROUND_UP(sizeof(struct andr_vnd_boot_img_hdr), desc->blksz);
134 bufsz = num_blks * desc->blksz;
135 buf = malloc(bufsz);
136 if (!buf)
137 return log_msg_ret("buf", -ENOMEM);
138
139 ret = blk_read(blk, partition.start, num_blks, buf);
140 if (ret != num_blks) {
141 free(buf);
142 return log_msg_ret("part read", -EIO);
143 }
144
145 if (!is_android_vendor_boot_image_header(buf)) {
146 free(buf);
147 return log_msg_ret("header", -ENOENT);
148 }
Julien Massonb238dee2024-11-21 11:59:55 +0100149
150 if (!android_image_get_vendor_bootimg_size(buf, &priv->vendor_boot_img_size)) {
151 free(buf);
152 return log_msg_ret("get vendor bootimg size", -EINVAL);
153 }
154
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200155 free(buf);
156
157 return 0;
158}
159
160static int android_read_slot_from_bcb(struct bootflow *bflow, bool decrement)
161{
162 struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
163 struct android_priv *priv = bflow->bootmeth_priv;
164 struct disk_partition misc;
165 char slot_suffix[3];
166 int ret;
167
Guillaume La Roquedf9e6412024-11-26 09:06:10 +0100168 if (!CONFIG_IS_ENABLED(ANDROID_AB)) {
169 priv->slot = NULL;
170 return 0;
171 }
172
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200173 ret = part_get_info_by_name(desc, BCB_PART_NAME, &misc);
174 if (ret < 0)
175 return log_msg_ret("part", ret);
176
177 ret = ab_select_slot(desc, &misc, decrement);
178 if (ret < 0)
179 return log_msg_ret("slot", ret);
180
Guillaume La Roquedf9e6412024-11-26 09:06:10 +0100181 priv->slot = malloc(SLOT_LEN);
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200182 priv->slot[0] = BOOT_SLOT_NAME(ret);
183 priv->slot[1] = '\0';
184
185 sprintf(slot_suffix, "_%s", priv->slot);
186 ret = bootflow_cmdline_set_arg(bflow, "androidboot.slot_suffix",
187 slot_suffix, false);
188 if (ret < 0)
189 return log_msg_ret("cmdl", ret);
190
191 return 0;
192}
193
194static int configure_serialno(struct bootflow *bflow)
195{
196 char *serialno = env_get("serial#");
197
198 if (!serialno)
199 return log_msg_ret("serial", -ENOENT);
200
201 return bootflow_cmdline_set_arg(bflow, "androidboot.serialno", serialno, false);
202}
203
Mattijs Korpershoekc818a712024-09-12 16:00:01 +0200204static int configure_bootloader_version(struct bootflow *bflow)
205{
206 return bootflow_cmdline_set_arg(bflow, "androidboot.bootloader",
207 PLAIN_VERSION, false);
208}
209
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200210static int android_read_bootflow(struct udevice *dev, struct bootflow *bflow)
211{
212 struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
213 struct disk_partition misc;
214 struct android_priv *priv;
215 char command[BCB_FIELD_COMMAND_SZ];
216 int ret;
217
218 bflow->state = BOOTFLOWST_MEDIA;
219
220 /*
221 * bcb_find_partition_and_load() will print errors to stdout
222 * if BCB_PART_NAME is not found. To avoid that, check if the
223 * partition exists first.
224 */
225 ret = part_get_info_by_name(desc, BCB_PART_NAME, &misc);
226 if (ret < 0)
227 return log_msg_ret("part", ret);
228
229 ret = bcb_find_partition_and_load("mmc", desc->devnum, BCB_PART_NAME);
230 if (ret < 0)
231 return log_msg_ret("bcb load", ret);
232
233 ret = bcb_get(BCB_FIELD_COMMAND, command, sizeof(command));
234 if (ret < 0)
235 return log_msg_ret("bcb read", ret);
236
237 priv = malloc(sizeof(struct android_priv));
238 if (!priv)
239 return log_msg_ret("buf", -ENOMEM);
240
241 if (!strcmp("bootonce-bootloader", command)) {
242 priv->boot_mode = ANDROID_BOOT_MODE_BOOTLOADER;
243 bflow->os_name = strdup("Android (bootloader)");
244 } else if (!strcmp("boot-fastboot", command)) {
245 priv->boot_mode = ANDROID_BOOT_MODE_RECOVERY;
246 bflow->os_name = strdup("Android (fastbootd)");
247 } else if (!strcmp("boot-recovery", command)) {
248 priv->boot_mode = ANDROID_BOOT_MODE_RECOVERY;
249 bflow->os_name = strdup("Android (recovery)");
250 } else {
251 priv->boot_mode = ANDROID_BOOT_MODE_NORMAL;
252 bflow->os_name = strdup("Android");
253 }
254 if (!bflow->os_name)
255 return log_msg_ret("os", -ENOMEM);
256
257 if (priv->boot_mode == ANDROID_BOOT_MODE_BOOTLOADER) {
258 /* Clear BCB */
259 memset(command, 0, sizeof(command));
260 ret = bcb_set(BCB_FIELD_COMMAND, command);
261 if (ret < 0) {
262 free(priv);
263 return log_msg_ret("bcb set", ret);
264 }
265 ret = bcb_store();
266 if (ret < 0) {
267 free(priv);
268 return log_msg_ret("bcb store", ret);
269 }
270
271 bflow->bootmeth_priv = priv;
272 bflow->state = BOOTFLOWST_READY;
273 return 0;
274 }
275
276 bflow->bootmeth_priv = priv;
277
278 /* For recovery and normal boot, we need to scan the partitions */
279 ret = android_read_slot_from_bcb(bflow, false);
280 if (ret < 0) {
281 log_err("read slot: %d", ret);
282 goto free_priv;
283 }
284
285 ret = scan_boot_part(bflow->blk, priv);
286 if (ret < 0) {
287 log_debug("scan boot failed: err=%d\n", ret);
288 goto free_priv;
289 }
290
Guillaume La Roque4b501112024-11-26 09:06:09 +0100291 if (priv->header_version >= 3) {
292 ret = scan_vendor_boot_part(bflow->blk, priv);
293 if (ret < 0) {
294 log_debug("scan vendor_boot failed: err=%d\n", ret);
295 goto free_priv;
296 }
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200297 }
298
Mattijs Korpershoekc818a712024-09-12 16:00:01 +0200299 /*
300 * Ignoring return code for the following configurations:
301 * these are not mandatory for booting.
302 */
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200303 configure_serialno(bflow);
Mattijs Korpershoekc818a712024-09-12 16:00:01 +0200304 configure_bootloader_version(bflow);
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200305
Guillaume La Roquedf9e6412024-11-26 09:06:10 +0100306 if (priv->boot_mode == ANDROID_BOOT_MODE_NORMAL && priv->slot) {
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200307 ret = bootflow_cmdline_set_arg(bflow, "androidboot.force_normal_boot",
308 "1", false);
309 if (ret < 0) {
310 log_debug("normal_boot %d", ret);
311 goto free_priv;
312 }
313 }
314
315 bflow->state = BOOTFLOWST_READY;
316
317 return 0;
318
319 free_priv:
320 free(priv);
321 bflow->bootmeth_priv = NULL;
322 return ret;
323}
324
325static int android_read_file(struct udevice *dev, struct bootflow *bflow,
326 const char *file_path, ulong addr, ulong *sizep)
327{
328 /*
329 * Reading individual files is not supported since we only
330 * operate on whole mmc devices (because we require multiple partitions)
331 */
332 return log_msg_ret("Unsupported", -ENOSYS);
333}
334
335/**
336 * read_slotted_partition() - Read a partition by appending a slot suffix
337 *
338 * Most modern Android devices use Seamless Updates, where each partition
339 * is duplicated. For example, the boot partition has boot_a and boot_b.
340 * For more information, see:
341 * https://source.android.com/docs/core/ota/ab
342 * https://source.android.com/docs/core/ota/ab/ab_implement
343 *
344 * @blk: Block device to read
345 * @name: Partition name to read
346 * @slot: Nul-terminated slot suffixed to partition name ("a\0" or "b\0")
Julien Massonb238dee2024-11-21 11:59:55 +0100347 * @image_size: Image size in bytes used when reading the partition
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200348 * @addr: Address where the partition content is loaded into
349 * Return: 0 if OK, negative errno on failure.
350 */
351static int read_slotted_partition(struct blk_desc *desc, const char *const name,
Julien Massonb238dee2024-11-21 11:59:55 +0100352 const char slot[2], ulong image_size, ulong addr)
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200353{
354 struct disk_partition partition;
355 char partname[PART_NAME_LEN];
Guillaume La Roquedf9e6412024-11-26 09:06:10 +0100356 size_t partname_len;
Julien Massonb238dee2024-11-21 11:59:55 +0100357 ulong num_blks = DIV_ROUND_UP(image_size, desc->blksz);
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200358 int ret;
359 u32 n;
360
Guillaume La Roquedf9e6412024-11-26 09:06:10 +0100361 /*
362 * Ensure name fits in partname.
363 * For A/B, it should be <name>_<slot>\0
364 * For non A/B, it should be <name>\0
365 */
366 if (CONFIG_IS_ENABLED(ANDROID_AB))
367 partname_len = PART_NAME_LEN - 2 - 1;
368 else
369 partname_len = PART_NAME_LEN - 1;
370
371 if (strlen(name) > partname_len)
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200372 return log_msg_ret("name too long", -EINVAL);
373
Guillaume La Roquedf9e6412024-11-26 09:06:10 +0100374 if (slot)
375 sprintf(partname, "%s_%s", name, slot);
376 else
377 sprintf(partname, "%s", name);
378
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200379 ret = part_get_info_by_name(desc, partname, &partition);
380 if (ret < 0)
381 return log_msg_ret("part", ret);
382
Julien Massonb238dee2024-11-21 11:59:55 +0100383 n = blk_dread(desc, partition.start, num_blks, map_sysmem(addr, 0));
384 if (n < num_blks)
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200385 return log_msg_ret("part read", -EIO);
386
387 return 0;
388}
389
390#if CONFIG_IS_ENABLED(AVB_VERIFY)
391static int avb_append_commandline_arg(struct bootflow *bflow, char *arg)
392{
393 char *key = strsep(&arg, "=");
394 char *value = arg;
395 int ret;
396
397 ret = bootflow_cmdline_set_arg(bflow, key, value, false);
398 if (ret < 0)
399 return log_msg_ret("avb cmdline", ret);
400
401 return 0;
402}
403
404static int avb_append_commandline(struct bootflow *bflow, char *cmdline)
405{
406 char *arg = strsep(&cmdline, " ");
407 int ret;
408
409 while (arg) {
410 ret = avb_append_commandline_arg(bflow, arg);
411 if (ret < 0)
412 return ret;
413
414 arg = strsep(&cmdline, " ");
415 }
416
417 return 0;
418}
419
420static int run_avb_verification(struct bootflow *bflow)
421{
422 struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
423 struct android_priv *priv = bflow->bootmeth_priv;
424 const char * const requested_partitions[] = {"boot", "vendor_boot"};
425 struct AvbOps *avb_ops;
426 AvbSlotVerifyResult result;
427 AvbSlotVerifyData *out_data;
428 enum avb_boot_state boot_state;
429 char *extra_args;
Guillaume La Roquedf9e6412024-11-26 09:06:10 +0100430 char slot_suffix[3] = "";
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200431 bool unlocked = false;
432 int ret;
433
434 avb_ops = avb_ops_alloc(desc->devnum);
435 if (!avb_ops)
436 return log_msg_ret("avb ops", -ENOMEM);
437
Guillaume La Roquedf9e6412024-11-26 09:06:10 +0100438 if (priv->slot)
439 sprintf(slot_suffix, "_%s", priv->slot);
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200440
441 ret = avb_ops->read_is_device_unlocked(avb_ops, &unlocked);
442 if (ret != AVB_IO_RESULT_OK)
443 return log_msg_ret("avb lock", -EIO);
444
445 result = avb_slot_verify(avb_ops,
446 requested_partitions,
447 slot_suffix,
448 unlocked,
449 AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
450 &out_data);
451
452 if (result != AVB_SLOT_VERIFY_RESULT_OK) {
453 printf("Verification failed, reason: %s\n",
454 str_avb_slot_error(result));
455 avb_slot_verify_data_free(out_data);
456 return log_msg_ret("avb verify", -EIO);
457 }
458
459 if (unlocked)
460 boot_state = AVB_ORANGE;
461 else
462 boot_state = AVB_GREEN;
463
464 extra_args = avb_set_state(avb_ops, boot_state);
465 if (extra_args) {
466 /* extra_args will be modified after this. This is fine */
467 ret = avb_append_commandline_arg(bflow, extra_args);
468 if (ret < 0)
469 goto free_out_data;
470 }
471
472 ret = avb_append_commandline(bflow, out_data->cmdline);
473 if (ret < 0)
474 goto free_out_data;
475
476 return 0;
477
478 free_out_data:
479 if (out_data)
480 avb_slot_verify_data_free(out_data);
481
482 return log_msg_ret("avb cmdline", ret);
483}
484#else
485static int run_avb_verification(struct bootflow *bflow)
486{
487 int ret;
488
489 /* When AVB is unsupported, pass ORANGE state */
490 ret = bootflow_cmdline_set_arg(bflow,
491 "androidboot.verifiedbootstate",
492 "orange", false);
493 if (ret < 0)
494 return log_msg_ret("avb cmdline", ret);
495
496 return 0;
497}
498#endif /* AVB_VERIFY */
499
500static int boot_android_normal(struct bootflow *bflow)
501{
502 struct blk_desc *desc = dev_get_uclass_plat(bflow->blk);
503 struct android_priv *priv = bflow->bootmeth_priv;
504 int ret;
505 ulong loadaddr = env_get_hex("loadaddr", 0);
506 ulong vloadaddr = env_get_hex("vendor_boot_comp_addr_r", 0);
507
508 ret = run_avb_verification(bflow);
509 if (ret < 0)
510 return log_msg_ret("avb", ret);
511
512 /* Read slot once more to decrement counter from BCB */
513 ret = android_read_slot_from_bcb(bflow, true);
514 if (ret < 0)
515 return log_msg_ret("read slot", ret);
516
Julien Massonb238dee2024-11-21 11:59:55 +0100517 ret = read_slotted_partition(desc, "boot", priv->slot, priv->boot_img_size,
518 loadaddr);
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200519 if (ret < 0)
520 return log_msg_ret("read boot", ret);
521
Guillaume La Roque4b501112024-11-26 09:06:09 +0100522 if (priv->header_version >= 3) {
Julien Massonb238dee2024-11-21 11:59:55 +0100523 ret = read_slotted_partition(desc, "vendor_boot", priv->slot,
524 priv->vendor_boot_img_size, vloadaddr);
Guillaume La Roque4b501112024-11-26 09:06:09 +0100525 if (ret < 0)
526 return log_msg_ret("read vendor_boot", ret);
527 set_avendor_bootimg_addr(vloadaddr);
528 }
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200529 set_abootimg_addr(loadaddr);
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200530
Guillaume La Roquedf9e6412024-11-26 09:06:10 +0100531 if (priv->slot)
532 free(priv->slot);
533
Mattijs Korpershoekb30baa92024-07-10 10:40:05 +0200534 ret = bootm_boot_start(loadaddr, bflow->cmdline);
535
536 return log_msg_ret("boot", ret);
537}
538
539static int boot_android_recovery(struct bootflow *bflow)
540{
541 int ret;
542
543 ret = boot_android_normal(bflow);
544
545 return log_msg_ret("boot", ret);
546}
547
548static int boot_android_bootloader(struct bootflow *bflow)
549{
550 int ret;
551
552 ret = run_command("fastboot usb 0", 0);
553 do_reset(NULL, 0, 0, NULL);
554
555 return log_msg_ret("boot", ret);
556}
557
558static int android_boot(struct udevice *dev, struct bootflow *bflow)
559{
560 struct android_priv *priv = bflow->bootmeth_priv;
561 int ret;
562
563 switch (priv->boot_mode) {
564 case ANDROID_BOOT_MODE_NORMAL:
565 ret = boot_android_normal(bflow);
566 break;
567 case ANDROID_BOOT_MODE_RECOVERY:
568 ret = boot_android_recovery(bflow);
569 break;
570 case ANDROID_BOOT_MODE_BOOTLOADER:
571 ret = boot_android_bootloader(bflow);
572 break;
573 default:
574 printf("ANDROID: Unknown boot mode %d. Running fastboot...\n",
575 priv->boot_mode);
576 boot_android_bootloader(bflow);
577 /* Tell we failed to boot since boot mode is unknown */
578 ret = -EFAULT;
579 }
580
581 return ret;
582}
583
584static int android_bootmeth_bind(struct udevice *dev)
585{
586 struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev);
587
588 plat->desc = "Android boot";
589 plat->flags = BOOTMETHF_ANY_PART;
590
591 return 0;
592}
593
594static struct bootmeth_ops android_bootmeth_ops = {
595 .check = android_check,
596 .read_bootflow = android_read_bootflow,
597 .read_file = android_read_file,
598 .boot = android_boot,
599};
600
601static const struct udevice_id android_bootmeth_ids[] = {
602 { .compatible = "u-boot,android" },
603 { }
604};
605
606U_BOOT_DRIVER(bootmeth_android) = {
607 .name = "bootmeth_android",
608 .id = UCLASS_BOOTMETH,
609 .of_match = android_bootmeth_ids,
610 .ops = &android_bootmeth_ops,
611 .bind = android_bootmeth_bind,
612};