blob: e84af6025855f07e34005fd005c332b724369cf9 [file] [log] [blame]
Bo Lv72d0e902023-01-02 14:27:34 +00001// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2/*
3 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
4 */
5
6#include <common.h>
7#include <command.h>
8#include <env.h>
9#include <malloc.h>
10#include <asm/byteorder.h>
11#include <config.h>
12#include <asm/amlogic/arch/io.h>
13#include <amlogic/partition_table.h>
14#include <amlogic/libavb/libavb.h>
15#include <amlogic/emmc_partitions.h>
16#include <amlogic/storage.h>
17#include <asm/amlogic/arch/bl31_apis.h>
18#if defined(CONFIG_AML_ANTIROLLBACK) || defined(CONFIG_AML_AVB2_ANTIROLLBACK)
19#include <amlogic/anti-rollback.h>
20#endif
21#include <version.h>
22#include <amlogic/aml_efuse.h>
23#include <amlogic/store_wrapper.h>
Mingyen Hung6e468002023-01-04 23:43:04 -080024#include <fs.h>
25#include <fat.h>
26#include <factory_provision/factory_provision_utils.h>
Bo Lv72d0e902023-01-02 14:27:34 +000027
28#define AVB_USE_TESTKEY
29#define MAX_DTB_SIZE (AML_DTB_IMG_MAX_SZ + 512)
30#define DTB_PARTITION_SIZE 258048
31#define AVB_NUM_SLOT (4)
Bo Lv72d0e902023-01-02 14:27:34 +000032
33/* use max nand page size, 4K */
34#define NAND_PAGE_SIZE (0x1000)
35
36#define CONFIG_AVB2_KPUB_EMBEDDED
37
Matthew Shyuc710a122023-12-14 00:08:41 -080038// The last slot is reserved for recovery partition
39#define RECOVERY_ARB_LOCATION (31)
Bo Lv72d0e902023-01-02 14:27:34 +000040#ifdef CONFIG_AVB2_KPUB_VENDOR
41extern const char avb2_kpub_vendor[];
42extern const int avb2_kpub_vendor_len;
43#endif /* CONFIG_AVB_KPUB_VENDOR */
44
45extern const char avb2_kpub_default[];
46extern const int avb2_kpub_default_len;
47extern const char avb2_kpub_production[];
48extern const int avb2_kpub_production_len;
49
50#ifndef CONFIG_AVB2_KPUB_FROM_FIP
51#define CONFIG_AVB2_KPUB_FROM_FIP (0)
52#endif
53
54#if CONFIG_AVB2_KPUB_FROM_FIP
55int compare_avbkey_with_fipkey(const uint8_t* public_key_data, size_t public_key_length);
56#endif
57
Matthew Shyuc710a122023-12-14 00:08:41 -080058void *memory_addr;
Bo Lv72d0e902023-01-02 14:27:34 +000059AvbOps avb_ops_;
Matthew Shyuc710a122023-12-14 00:08:41 -080060int run_in_recovery;
Bo Lv72d0e902023-01-02 14:27:34 +000061
62static AvbIOResult read_from_partition(AvbOps *ops, const char *partition, int64_t offset,
63 size_t num_bytes, void *buffer, size_t *out_num_read)
64{
65 int rc = 0;
66 uint64_t part_bytes = 0;
67 AvbIOResult result = AVB_IO_RESULT_OK;
68 size_t total_bytes = num_bytes;
69
70 if (ops->get_size_of_partition(ops, partition, &part_bytes) != AVB_IO_RESULT_OK) {
71 result = AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
72 goto out;
73 }
74
75 if (part_bytes < offset) {
76 result = AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION;
77 goto out;
78 }
79
80 *out_num_read = 0;
81 if (!strcmp(partition, "dt_a") || !strcmp(partition, "dt_b") ||
82 !strcmp(partition, "dt")) {
83 char *dtb_buf = malloc(MAX_DTB_SIZE);
84
85 if (!dtb_buf) {
86 result = AVB_IO_RESULT_ERROR_OOM;
87 goto out;
88 }
89
90 /* rc = store_dtb_rw(dtb_buf, MAX_DTB_SIZE, 2); */
91 memset(dtb_buf, 0x00, MAX_DTB_SIZE);
92 rc = store_rsv_read("dtb", MAX_DTB_SIZE, (void *)dtb_buf);
93 if (rc) {
94 printf("Failed to read dtb\n");
95 free(dtb_buf);
96 result = AVB_IO_RESULT_ERROR_IO;
97 goto out;
98 } else {
99 *out_num_read = num_bytes > MAX_DTB_SIZE ? MAX_DTB_SIZE : num_bytes;
100 memcpy(buffer, dtb_buf, *out_num_read);
101 free(dtb_buf);
102 result = AVB_IO_RESULT_OK;
103 goto out;
104 }
Matthew Shyuc710a122023-12-14 00:08:41 -0800105 } else if (!strcmp(partition, "recovery-memory")) {
106 u32 filesize = simple_strtoul(env_get("filesize"), NULL, 16);
107
108 if (memory_addr) {
109 num_bytes = (filesize - offset >= num_bytes) ? num_bytes :
110 (filesize - offset);
111 memcpy(buffer, (uint8_t *)(memory_addr + offset), num_bytes);
112 *out_num_read = num_bytes;
113 return AVB_IO_RESULT_OK;
114 }
115 return AVB_IO_RESULT_ERROR_IO;
Bo Lv72d0e902023-01-02 14:27:34 +0000116 } else {
117 enum boot_type_e type = store_get_type();
118
119 /* There is only 1 recovery partition even in A/B */
120 if (!strcmp(partition, "recovery_a") ||
121 !strcmp(partition, "recovery_b") ||
122 !strcmp(partition, "recovery"))
123 partition = "recovery";
124
125 if (type == BOOT_NAND_MTD || type == BOOT_SNAND) {
126 if (offset != 0) {
127 uint8_t *tmp_buf = malloc(NAND_PAGE_SIZE);
128 int64_t align = offset & ~(NAND_PAGE_SIZE - 1);
129 int64_t drop_bytes = offset - align;
130 int32_t valid_data = NAND_PAGE_SIZE - drop_bytes;
131
132 if (!tmp_buf) {
133 printf("failed to allocate tmp buf for nand\n");
134 result = AVB_IO_RESULT_ERROR_IO;
135 goto out;
136 }
137
138 rc = store_logic_read(partition, align, NAND_PAGE_SIZE, tmp_buf);
139 if (rc) {
140 free(tmp_buf);
141 printf("part 1: Failed to read %dB from part[%s] at %lld\n",
142 NAND_PAGE_SIZE, partition, align);
143 result = AVB_IO_RESULT_ERROR_IO;
144 goto out;
145 } else {
146 if (num_bytes > valid_data) {
147 memcpy(buffer, tmp_buf + drop_bytes, valid_data);
148 num_bytes -= valid_data;
Mingyen Hung6e468002023-01-04 23:43:04 -0800149 buffer = (uint8_t *)buffer + valid_data;
Bo Lv72d0e902023-01-02 14:27:34 +0000150 } else {
151 memcpy(buffer, tmp_buf + drop_bytes, num_bytes);
152 num_bytes = 0;
153 }
154 offset = align + NAND_PAGE_SIZE;
155 free(tmp_buf);
156 }
Mingyen Hung6e468002023-01-04 23:43:04 -0800157 if (num_bytes > 0) {
158 rc = store_logic_read(partition, offset,
159 num_bytes, buffer);
160 printf("Failed to read");
161 printf("%zdB from part[%s] at %lld\n",
162 num_bytes, partition, offset);
163 }
Bo Lv72d0e902023-01-02 14:27:34 +0000164 } else {
165 rc = store_logic_read(partition, 0, num_bytes, buffer);
166 }
167 } else {
168 rc = store_read(partition, offset, num_bytes, buffer);
169 }
170
171 if (rc) {
172 printf("Part 2 Failed to read %zdB from part[%s] at %lld\n",
173 num_bytes, partition, offset);
174 result = AVB_IO_RESULT_ERROR_IO;
175 goto out;
176 }
177 *out_num_read = total_bytes;
178 }
179
180out:
181 return result;
182}
183
184static AvbIOResult write_to_partition(AvbOps *ops, const char *partition,
185 int64_t offset, size_t num_bytes, const void *buffer)
186{
187 int rc = 0;
188 uint64_t part_bytes = 0;
189 AvbIOResult result = AVB_IO_RESULT_OK;
190
191 if (ops->get_size_of_partition(ops, partition, &part_bytes) != AVB_IO_RESULT_OK) {
192 result = AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
193 goto out;
194 }
195 if (part_bytes < offset) {
196 result = AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION;
197 goto out;
198 }
199
200 if (!strcmp(partition, "dt_a") || !strcmp(partition, "dt_b") ||
201 !strcmp(partition, "dt")) {
202 if (offset)
203 return AVB_IO_RESULT_ERROR_IO;
204 /* rc = store_dtb_rw((void *)buffer, num_bytes, 1); */
205 rc = store_rsv_write("dtb", num_bytes, (void *)buffer);
206 if (rc) {
207 printf("Failed to write dtb\n");
208 result = AVB_IO_RESULT_ERROR_IO;
209 goto out;
210 } else {
211 result = AVB_IO_RESULT_OK;
212 goto out;
213 }
214 } else {
215 /* There is only 1 recovery partition even in A/B */
216 if (!strcmp(partition, "recovery_a") ||
217 !strcmp(partition, "recovery_b") ||
218 !strcmp(partition, "recovery"))
219 rc = store_write("recovery", offset, num_bytes, (unsigned char *)buffer);
220 else
221 rc = store_write(partition, offset, num_bytes, (unsigned char *)buffer);
222 if (rc) {
223 printf("Failed to write %zdB from part[%s] at %lld\n",
224 num_bytes, partition, offset);
225 result = AVB_IO_RESULT_ERROR_IO;
226 goto out;
227 }
228 }
229
230out:
231 return result;
232}
233
234static AvbIOResult get_unique_guid_for_partition(AvbOps *ops, const char *partition,
235 char *guid_buf, size_t guid_buf_size)
236{
237 char *s1;
238 int ret;
239 char part_name[128];
240
241 memset(guid_buf, 0, guid_buf_size);
242 s1 = env_get("active_slot");
243 if (!s1) {
244 run_command("get_valid_slot;", 0);
245 s1 = env_get("active_slot");
246 }
247 //printf("active_slot is %s\n", s1);
248 if (!memcmp(partition, "system", strlen("system"))) {
249 if (s1 && (strcmp(s1, "_a") == 0))
250 ret = get_partition_num_by_name("system_a");
251 else if (s1 && (strcmp(s1, "_b") == 0))
252 ret = get_partition_num_by_name("system_b");
253 else
254 ret = get_partition_num_by_name("system");
255
256 if (ret >= 0) {
257 sprintf(part_name, "/dev/mmcblk0p%d", ret + 1);
258 strncpy(guid_buf, part_name, guid_buf_size);
259 } else {
260 printf("system part isn't exist\n");
261 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
262 }
263 } else if (!memcmp(partition, "vbmeta", strlen("vbmeta"))) {
264 strncpy(guid_buf, "/dev/block/vbmeta", guid_buf_size);
265 }
266 return AVB_IO_RESULT_OK;
267}
268
269static AvbIOResult get_size_of_partition(AvbOps *ops, const char *partition,
270 uint64_t *out_size_num_bytes)
271{
272 uint64_t rc = 0;
273
274 if (!strcmp(partition, "dt_a") || !strcmp(partition, "dt_b") ||
275 !strcmp(partition, "dt")) {
276 *out_size_num_bytes = DTB_PARTITION_SIZE;
Matthew Shyuc710a122023-12-14 00:08:41 -0800277 } else if (!strcmp(partition, "recovery-memory")) {
278 *out_size_num_bytes = simple_strtoul(env_get("filesize"), NULL, 16);
Bo Lv72d0e902023-01-02 14:27:34 +0000279 } else {
280 /* There is only 1 recovery partition even in A/B */
281 if (!strcmp(partition, "recovery_a") ||
282 !strcmp(partition, "recovery_b") ||
283 !strcmp(partition, "recovery"))
284 rc = store_logic_cap("recovery");
285 else
286 rc = store_logic_cap(partition);
287 if (rc == 1) {
288 printf("Failed to get partition[%s] size\n", partition);
289 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
290 }
291 *out_size_num_bytes = rc;
292 }
293
294 return AVB_IO_RESULT_OK;
295}
296
297/**
298 * normally, we should read vendor avb public key from a virtual partition with the name avb_custom_key.
299 * Flashing and erasing this partition only works in the UNLOCKED state. Setting the custom key is done like this:
300 * $ avbtool extract_public_key --key key.pem --output pkmd.bin
301 * $ fastboot flash avb_custom_key pkmd.bin
302 *
303 * Erasing the key is done by erasing the virtual partition:
304 * $ fastboot erase avb_custom_key
305 */
306static AvbIOResult validate_vbmeta_public_key(AvbOps *ops, const uint8_t *public_key_data,
307 size_t public_key_length, const uint8_t *public_key_metadata,
308 size_t public_key_metadata_length, bool *out_is_trusted)
309{
310 *out_is_trusted = false;
311 AvbIOResult ret = AVB_IO_RESULT_ERROR_IO;
312 char *keybuf = NULL;
313 char *partition = "misc";
314 AvbKey_t key;
315 int size = 0;
316#if CONFIG_AVB2_KPUB_FROM_FIP
317 int result = 0;
318#endif
319 int i = 0;
320
321#if CONFIG_AVB2_KPUB_FROM_FIP
322 printf("AVB2 verifying with fip key\n");
323 result = compare_avbkey_with_fipkey(public_key_data, public_key_length);
324 if (result == -2) {
325 printf("AVB2 verified with fip key failed\n");
326 *out_is_trusted = false;
327 ret = AVB_IO_RESULT_OK;
328 return ret;
329 } else if (result == -1) {
330 printf("AVB2 cannot find fip key\n");
331 } else if (result == 0) {
332 printf("AVB2 verified with fip key success\n");
333 *out_is_trusted = true;
334 ret = AVB_IO_RESULT_OK;
335 return ret;
336 }
337#endif
338
339 /*
340 * disable AVB custom key and test key
341 * if device secure boot enabled
342 */
343 if (!IS_FEAT_BOOT_VERIFY()) {
344 key.size = 0;
345 keybuf = (char *)malloc(AVB_CUSTOM_KEY_LEN_MAX);
346 if (keybuf) {
347 memset(keybuf, 0, AVB_CUSTOM_KEY_LEN_MAX);
348 size = store_part_size(partition);
349 if (size != 1) {
350 if (store_read((const char *)partition,
351 size - AVB_CUSTOM_KEY_LEN_MAX,
352 AVB_CUSTOM_KEY_LEN_MAX,
353 (unsigned char *)keybuf) >= 0) {
354 memcpy(&key, keybuf, sizeof(AvbKey_t));
355 }
356 }
357 }
358
359 if (keybuf && (strncmp(keybuf, "AVBK", 4) == 0)) {
360 printf("AVB2 verify with avb_custom_key\n");
361 if (key.size == public_key_length &&
362 !avb_safe_memcmp(public_key_data,
363 keybuf + sizeof(AvbKey_t), public_key_length)) {
364 *out_is_trusted = true;
365 ret = AVB_IO_RESULT_OK;
366 }
Jason Tong6a3cca92023-08-24 18:08:17 +0800367 if (is_device_unlocked())
368 ret = AVB_IO_RESULT_OK;
Bo Lv72d0e902023-01-02 14:27:34 +0000369 } else {
370 /**
371 * When the custom key is set
372 * and the device is in the LOCKED state
373 * it will boot images signed with both the built-in key
374 * as well as the custom key
375 */
376 printf("AVB2 verify with default kpub:%d, vbmeta kpub:%ld\n",
377 avb2_kpub_default_len, public_key_length);
378 if (avb2_kpub_default_len == public_key_length &&
379 !avb_safe_memcmp(public_key_data,
380 avb2_kpub_default, public_key_length)) {
381 *out_is_trusted = true;
382 ret = AVB_IO_RESULT_OK;
383 }
384 }
385 } else {
386 printf("AVB2 verify with production kpub:%d, vbmeta kpub:%ld\n",
387 avb2_kpub_production_len, public_key_length);
388 if (avb2_kpub_production_len == public_key_length &&
389 !avb_safe_memcmp(public_key_data,
390 avb2_kpub_production, public_key_length)) {
391 *out_is_trusted = true;
392 ret = AVB_IO_RESULT_OK;
393 }
394 for (i = 0; i < avb2_kpub_production_len; i++) {
395 if (avb2_kpub_production[i] != 0)
396 break;
397 }
398 if (i == avb2_kpub_production_len)
399 printf("ERROR: DID YOU FORGET TO CHANGE AVB2 KEY FOR SECURE BOOT?");
400 }
401
402 if (keybuf)
403 free(keybuf);
404 if (ret != AVB_IO_RESULT_OK)
405 printf("AVB2 key in bootloader does not match with the key in vbmeta\n");
406 return ret;
407}
408
Matthew Shyuc710a122023-12-14 00:08:41 -0800409static AvbIOResult validate_public_key_for_partition(AvbOps *ops,
410 const char *partition,
411 const u8 *public_key_data,
412 size_t public_key_length,
413 const u8 *public_key_metadata,
414 size_t public_key_metadata_length,
415 bool *out_is_trusted,
416 uint32_t *out_rollback_index_location
417)
418{
419 AvbIOResult ret = AVB_IO_RESULT_ERROR_IO;
420
421 if (!ops || !partition || !public_key_data || !out_is_trusted ||
422 !out_rollback_index_location)
423 return AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE;
424
425 *out_is_trusted = false;
426
427 if (!strcmp(partition, "recovery") ||
428 !strcmp(partition, "recovery-memory")) {
429 printf("checking for recovery partition\n");
430 ret = validate_vbmeta_public_key(ops, public_key_data,
431 public_key_length, public_key_metadata,
432 public_key_metadata_length,
433 out_is_trusted);
434 *out_rollback_index_location = RECOVERY_ARB_LOCATION;
435 } else {
436 *out_rollback_index_location = 0;
437 return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
438 }
439
440 return ret;
441}
442
Bo Lv72d0e902023-01-02 14:27:34 +0000443static AvbIOResult read_rollback_index(AvbOps *ops, size_t rollback_index_location,
444 uint64_t *out_rollback_index)
445{
Mingyen Hung6e468002023-01-04 23:43:04 -0800446 AvbIOResult result = AVB_IO_RESULT_OK;
Bo Lv72d0e902023-01-02 14:27:34 +0000447#if defined(CONFIG_AML_ANTIROLLBACK) || defined(CONFIG_AML_AVB2_ANTIROLLBACK)
Mingyen Hung6e468002023-01-04 23:43:04 -0800448 uint32_t version = 0;
Bo Lv72d0e902023-01-02 14:27:34 +0000449#endif
Mingyen Hung6e468002023-01-04 23:43:04 -0800450
451 *out_rollback_index = 0;
452
453#if defined(CONFIG_AML_ANTIROLLBACK) || defined(CONFIG_AML_AVB2_ANTIROLLBACK)
454 if (is_avb_arb_available()) {
455 if (get_avb_antirollback(rollback_index_location, &version)) {
456 *out_rollback_index = version;
457 } else {
458 printf("failed to read rollback index: %zd\n", rollback_index_location);
459 result = AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
460 }
461 }
462#endif
463
464 return result;
Bo Lv72d0e902023-01-02 14:27:34 +0000465}
466
467static AvbIOResult write_rollback_index(AvbOps* ops, size_t rollback_index_location,
468 uint64_t rollback_index)
469{
470 AvbIOResult result = AVB_IO_RESULT_OK;
Mingyen Hung6e468002023-01-04 23:43:04 -0800471
Bo Lv72d0e902023-01-02 14:27:34 +0000472#if defined(CONFIG_AML_ANTIROLLBACK) || defined(CONFIG_AML_AVB2_ANTIROLLBACK)
473 uint32_t version = rollback_index;
474
Mingyen Hung6e468002023-01-04 23:43:04 -0800475 if (is_avb_arb_available()) {
476 if (!set_avb_antirollback(rollback_index_location, version)) {
477 printf("failed to set rollback index: %zd, version: %u\n",
478 rollback_index_location, version);
479 result = AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
480 }
Bo Lv72d0e902023-01-02 14:27:34 +0000481 }
Bo Lv72d0e902023-01-02 14:27:34 +0000482#endif
Mingyen Hung6e468002023-01-04 23:43:04 -0800483
Bo Lv72d0e902023-01-02 14:27:34 +0000484 return result;
485}
486
487static AvbIOResult read_is_device_unlocked(AvbOps* ops, bool* out_is_unlocked)
488{
489 AvbIOResult result = AVB_IO_RESULT_OK;
Mingyen Hung6e468002023-01-04 23:43:04 -0800490 LockData_t info = { 0 };
Bo Lv72d0e902023-01-02 14:27:34 +0000491#if defined(CONFIG_AML_ANTIROLLBACK) || defined(CONFIG_AML_AVB2_ANTIROLLBACK)
Mingyen Hung6e468002023-01-04 23:43:04 -0800492 uint32_t lock_state = 0;
493#endif
494 char *lock_s = env_get("lock");
Bo Lv72d0e902023-01-02 14:27:34 +0000495
Mingyen Hung6e468002023-01-04 23:43:04 -0800496 if (!lock_s)
497 return AVB_IO_RESULT_ERROR_IO;
Bo Lv72d0e902023-01-02 14:27:34 +0000498
Mingyen Hung6e468002023-01-04 23:43:04 -0800499#if defined(CONFIG_AML_ANTIROLLBACK) || defined(CONFIG_AML_AVB2_ANTIROLLBACK)
500 if (is_avb_arb_available()) {
501 if (get_avb_lock_state(&lock_state)) {
502 *out_is_unlocked = !lock_state;
503 if (*out_is_unlocked)
504 lock_s[4] = '0';
505 else
506 lock_s[4] = '1';
507 } else {
508 printf("failed to read device lock status from rpmb\n");
509 result = AVB_IO_RESULT_ERROR_IO;
510 }
511 return result;
Bo Lv72d0e902023-01-02 14:27:34 +0000512 }
Mingyen Hung6e468002023-01-04 23:43:04 -0800513#endif
Bo Lv72d0e902023-01-02 14:27:34 +0000514
515 memset(&info, 0, sizeof(struct LockData));
Bo Lv72d0e902023-01-02 14:27:34 +0000516 info.version_major = (int)(lock_s[0] - '0');
517 info.version_minor = (int)(lock_s[1] - '0');
518 info.lock_state = (int)(lock_s[4] - '0');
519 info.lock_critical_state = (int)(lock_s[5] - '0');
520 info.lock_bootloader = (int)(lock_s[6] - '0');
521
522 if (info.lock_state == 1)
523 *out_is_unlocked = false;
524 else
525 *out_is_unlocked = true;
Mingyen Hung6e468002023-01-04 23:43:04 -0800526
Bo Lv72d0e902023-01-02 14:27:34 +0000527 return result;
528}
529
Mingyen Hung6e468002023-01-04 23:43:04 -0800530/* 4K bytes are allocated to store persistent value
531 * The first 4B is the persistent store magic word "@AVB"
532 * It is further divided into 132B slots
533 * Each 132B contains a persistent_value_t structure.
534 */
535#define AVB_PERSISTENT_MISC_OFFSET (2040 * 1024)
536#define AVB_PERSISTENT_SLOT (31)
537/* 4100 */
538#define AVB_PERSISTENT_SIZE (4 + 4 + 132 * AVB_PERSISTENT_SLOT)
539#define AVB_PERSISTENT_MAGIC "@AVB"
540#define AVB_PERSISTENT_VERSION (0x0)
541#define PERSISTENT_NAME_MAX_LEN (64)
542#define PERSISTENT_VALUE_MAX_LEN (64)
543#define PERSISTENT_FILENAME "avb_persist"
544
545#define DEV_NAME "mmc"
546#define DEV_NO (1)
547#define PART_TYPE "user"
548#define PART_NAME_RSV "rsv"
549#define PART_NAME_FTY "factory"
550#define NAND_FTY_MOUNT_PT "mnt"
551
552struct persistent_value {
553 uint8_t name_length;
554 uint8_t value_length;
555 uint16_t rsv;
556 char name[PERSISTENT_NAME_MAX_LEN];
557 uint8_t value[PERSISTENT_VALUE_MAX_LEN];
558};
559
560static uint8_t *persistent_store(int32_t *is_empty)
561{
562 uint8_t *buf = NULL;
563 int rc = 0;
564 loff_t act_read = 0;
565
566 /* initialize factory partition */
567 rc = run_command("factory_provision init", 0);
568 if (rc) {
569 printf("init factory partition failed\n");
570 return NULL;
571 }
572
573 buf = malloc(AVB_PERSISTENT_SIZE);
574 if (!buf) {
575 printf("failed to allocate buf for persistent store\n");
576 return NULL;
577 }
578 if (fat_read_file(PERSISTENT_FILENAME, buf, 0,
579 AVB_PERSISTENT_SIZE, &act_read)) {
580 printf("failed to read persistent store\n");
581 goto empty;
582 } else {
583 if (act_read != AVB_PERSISTENT_SIZE) {
584 printf("unexpected size: %lld\n", act_read);
585 memset(buf, 0, AVB_PERSISTENT_SIZE);
586 goto empty;
587 }
588 }
589
590empty:
591 if (memcmp(&buf[0], AVB_PERSISTENT_MAGIC, 4)) {
592 printf("empty persistent store, resetting\n");
593 memset(buf, 0, AVB_PERSISTENT_SIZE);
594 memcpy(&buf[0], AVB_PERSISTENT_MAGIC, 4);
595 if (is_empty)
596 *is_empty = 1;
597 } else {
598 if (is_empty)
599 *is_empty = 0;
600 }
601
602 return buf;
603}
604
605static AvbIOResult persistent_test(AvbOps *ops)
606{
607 AvbIOResult ret = AVB_IO_RESULT_OK;
608 static const char case_I[] = "smart wolves";
609 static const char case_II[] = "happy wife";
610 static const char case_III[] = "lion king";
611 char case_I_read[sizeof(case_I)] = {0};
612 char case_II_read[sizeof(case_II)] = {0};
613 char case_III_read[sizeof(case_III)] = {0};
614 size_t out_num_bytes_read = 0;
615
616 ret = ops->write_persistent_value(ops, "persist test case I",
617 sizeof(case_I), (const uint8_t *)case_I);
618 if (ret != AVB_IO_RESULT_OK) {
619 printf("failed to write case I\n");
620 return ret;
621 }
622 ret = ops->write_persistent_value(ops, "persist test case II",
623 sizeof(case_II), (const uint8_t *)case_II);
624 if (ret != AVB_IO_RESULT_OK) {
625 printf("failed to write case II\n");
626 return ret;
627 }
628 ret = ops->write_persistent_value(ops, "persist test case III",
629 sizeof(case_III), (const uint8_t *)case_III);
630 if (ret != AVB_IO_RESULT_OK) {
631 printf("failed to write case III\n");
632 return ret;
633 }
634
635 ret = ops->read_persistent_value(ops, "persist test case I",
636 sizeof(case_I_read), (uint8_t *)case_I_read, &out_num_bytes_read);
637 if (ret != AVB_IO_RESULT_OK) {
638 printf("failed to read case I\n");
639 return ret;
640 }
641 if (out_num_bytes_read == sizeof(case_I_read) &&
642 !strncmp(case_I, case_I_read, sizeof(case_I))) {
643 printf("case I passed\n");
644 } else {
645 printf("case I failed\n");
646 }
647
648 ret = ops->read_persistent_value(ops, "persist test case II",
649 sizeof(case_II_read), (uint8_t *)case_II_read,
650 &out_num_bytes_read);
651 if (ret != AVB_IO_RESULT_OK) {
652 printf("failed to read case II\n");
653 return ret;
654 }
655 if (out_num_bytes_read == sizeof(case_II_read) &&
656 !strncmp(case_II, case_II_read, sizeof(case_II))) {
657 printf("case II passed\n");
658 } else {
659 printf("case II failed\n");
660 }
661
662 ret = ops->read_persistent_value(ops, "persist test case III",
663 sizeof(case_III_read), (uint8_t *)case_III_read,
664 &out_num_bytes_read);
665 if (ret != AVB_IO_RESULT_OK) {
666 printf("failed to read case III\n");
667 return ret;
668 }
669 if (out_num_bytes_read == sizeof(case_III_read) &&
670 !strncmp(case_III, case_III_read, sizeof(case_III))) {
671 printf("case III passed\n");
672 } else {
673 printf("case III failed\n");
674 }
675
676 return ret;
677}
678
679uint32_t create_csrs(void)
680{
681 int part_num = get_partition_num_by_name(PART_NAME_FTY);
682 char part_name[32] = {0};
683 char cmd[64] = {0};
684 uint8_t buf[1] = {0};
685
686 if (part_num >= 0)
687 strcpy(part_name, PART_NAME_FTY);
688 else
689 strcpy(part_name, PART_NAME_RSV);
690
691 sprintf(cmd, "fatmkdir %s 0x%X:0x%X %s", DEV_NAME, DEV_NO,
692 get_partition_num_by_name(part_name), "csrs");
693 if (run_command(cmd, 0)) {
694 printf("command[%s] failed\n", cmd);
695 return AVB_IO_RESULT_ERROR_IO;
696 }
697
698 memset(cmd, 0, sizeof(cmd));
699
700 sprintf(cmd, "fatwrite %s 0x%X:0x%X 0x%08X %s 0x%X", DEV_NAME, DEV_NO,
701 get_partition_num_by_name(part_name),
702 (uint32_t)virt_to_phys((void *)buf), "csrs/csrs.json", 1);
703 if (run_command(cmd, 0)) {
704 printf("command[%s] failed\n", cmd);
705 return AVB_IO_RESULT_ERROR_IO;
706 }
707 return AVB_IO_RESULT_OK;
708}
709
710static AvbIOResult write_persistent_to_factory(uint8_t *buf, uint32_t size)
711{
712 int part_num = get_partition_num_by_name(PART_NAME_FTY);
713 char part_name[32] = {0};
714 char cmd[64] = {0};
715
716 if (part_num >= 0)
717 strcpy(part_name, PART_NAME_FTY);
718 else
719 strcpy(part_name, PART_NAME_RSV);
720
721 sprintf(cmd, "fatwrite %s 0x%X:0x%X 0x%08X %s 0x%X", DEV_NAME, DEV_NO,
722 get_partition_num_by_name(part_name),
723 (uint32_t)virt_to_phys((void *)buf), PERSISTENT_FILENAME, size);
724 if (run_command(cmd, 0)) {
725 printf("command[%s] failed\n", cmd);
726 return AVB_IO_RESULT_ERROR_IO;
727 }
728
729 return AVB_IO_RESULT_OK;
730}
731
732static AvbIOResult persistent_wipe(void)
733{
734 uint8_t *buf = NULL;
735 AvbIOResult ret = AVB_IO_RESULT_OK;
736
737 buf = persistent_store(NULL);
738 if (buf) {
739 memset(buf, 0, AVB_PERSISTENT_SIZE);
740 memcpy(&buf[0], AVB_PERSISTENT_MAGIC, 4);
741 *(uint32_t *)&buf[4] = AVB_PERSISTENT_VERSION;
742 } else {
743 return AVB_IO_RESULT_ERROR_IO;
744 }
745
746 ret = write_persistent_to_factory(buf, AVB_PERSISTENT_SIZE);
747
748 free(buf);
749 return ret;
750}
751
752static AvbIOResult persistent_dump(void)
753{
754 uint8_t *buf = NULL;
755 int rc = 0;
756 AvbIOResult ret = AVB_IO_RESULT_OK;
757 char *name = NULL;
758 int i = 0;
759 char cmd[64] = {0};
760 struct persistent_value *persist = NULL;
761
762 buf = persistent_store(NULL);
763 if (buf) {
764 printf("persistent store:\n");
765 /* skip magic word and version */
766 persist = (struct persistent_value *)(buf + 8);
767 for (i = 0; i < AVB_PERSISTENT_SLOT; i++) {
768 printf("%d:\n", i);
769 if (persist[i].name_length) {
770 name = malloc(persist[i].name_length);
771 if (!name) {
772 printf("failed to allocate name\n");
773 goto out;
774 }
775 strncpy(name, persist[i].name,
776 persist[i].name_length);
777 printf("%s\n", name);
778 free(name);
779 printf("length = %d\n",
780 persist[i].value_length);
781 snprintf(cmd, sizeof(cmd),
782 "md.b %p %x", persist[i].value,
783 persist[i].value_length);
784 rc = run_command(cmd, 0);
785 if (rc) {
786 printf("failed to run cmd: %s\n", cmd);
787 ret = AVB_IO_RESULT_ERROR_IO;
788 goto out;
789 }
790 } else {
791 printf("empty slot\n");
792 }
793 }
794 } else {
795 return AVB_IO_RESULT_ERROR_IO;
796 }
797
798out:
799 free(buf);
800 return ret;
801}
802
803AvbIOResult read_persistent_value(AvbOps *ops, const char *name,
804 size_t buffer_size, uint8_t *out_buffer, size_t *out_num_bytes_read)
805{
806 uint8_t *buf = NULL;
807 uint32_t value_found = 0;
808 uint32_t i = 0;
809 struct persistent_value *persist = NULL;
810 AvbIOResult ret = AVB_IO_RESULT_OK;
811 AvbIOResult ret_write = AVB_IO_RESULT_OK;
812 int32_t is_empty = 0;
813
814 if (!out_buffer) {
815 if (!buffer_size)
816 return AVB_IO_RESULT_OK;
817 else
818 return AVB_IO_RESULT_ERROR_IO;
819 }
820
821 buf = persistent_store(&is_empty);
822 if (buf) {
823 /* skip magic word and version */
824 persist = (struct persistent_value *)(buf + 8);
825 for (i = 0; i < AVB_PERSISTENT_SLOT; i++) {
826 if (strlen(name) == persist[i].name_length &&
827 !strncmp(persist[i].name, name, persist[i].name_length)) {
828 if (buffer_size >= persist[i].value_length) {
829 memcpy(out_buffer, persist[i].value,
830 persist[i].value_length);
831 *out_num_bytes_read = persist[i].value_length;
832 ret = AVB_IO_RESULT_OK;
833 } else {
834 ret = AVB_IO_RESULT_ERROR_INSUFFICIENT_SPACE;
835 *out_num_bytes_read = persist[i].value_length;
836 }
837 value_found = 1;
838 break;
839 }
840 }
841 if (!value_found)
842 ret = AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
843 } else {
844 ret = AVB_IO_RESULT_ERROR_IO;
845 }
846
847 /* write storage, if empty */
848 if (is_empty) {
849 ret_write = write_persistent_to_factory(buf, AVB_PERSISTENT_SIZE);
850 if (ret_write != AVB_IO_RESULT_OK)
851 printf("failed to write empty persistent data\n");
852 }
853
854 free(buf);
855 return ret;
856}
857
858AvbIOResult write_persistent_value(AvbOps *ops, const char *name,
859 size_t value_size, const uint8_t *value)
860{
861 uint8_t *buf = NULL;
862 struct persistent_value *empty_slot = NULL;
863 uint32_t value_found = 0;
864 uint32_t i = 0;
865 struct persistent_value *persist = NULL;
866 AvbIOResult ret = AVB_IO_RESULT_OK;
867
868 if (value_size > PERSISTENT_VALUE_MAX_LEN)
869 return AVB_IO_RESULT_ERROR_INVALID_VALUE_SIZE;
870 if (strlen(name) > PERSISTENT_NAME_MAX_LEN)
871 return AVB_IO_RESULT_ERROR_NO_SUCH_VALUE;
872
873 buf = persistent_store(NULL);
874 if (buf) {
875 /* skip magic word and version */
876 persist = (struct persistent_value *)(buf + 8);
877 for (i = 0; i < AVB_PERSISTENT_SLOT; i++) {
878 if (!persist[i].name_length) {
879 if (!empty_slot)
880 empty_slot = &persist[i];
881 } else {
882 if (strlen(name) == persist[i].name_length &&
883 !strncmp(persist[i].name, name,
884 persist[i].name_length)) {
885 memset(persist[i].value, 0, sizeof(persist[i].value));
886 memcpy(persist[i].value, value, value_size);
887 persist[i].value_length = value_size;
888 value_found = 1;
889 break;
890 }
891 }
892 }
893 if (!value_found) {
894 if (empty_slot) {
895 empty_slot->name_length = strlen(name);
896 memset(empty_slot->name, 0, sizeof(empty_slot->name));
897 memcpy(empty_slot->name, name, empty_slot->name_length);
898 memset(empty_slot->value, 0, sizeof(empty_slot->value));
899 memcpy(empty_slot->value, value, value_size);
900 empty_slot->value_length = value_size;
901 } else {
902 printf("no more slots\n");
903 ret = AVB_IO_RESULT_ERROR_IO;
904 goto out;
905 }
906 }
907 } else {
908 ret = AVB_IO_RESULT_ERROR_IO;
909 goto out;
910 }
911 ret = write_persistent_to_factory(buf, AVB_PERSISTENT_SIZE);
912
913out:
914 free(buf);
915 return ret;
916}
917
Bo Lv72d0e902023-01-02 14:27:34 +0000918static int avb_init(void)
919{
Mingyen Hung6e468002023-01-04 23:43:04 -0800920 int factory_part_num = get_partition_num_by_name(PART_NAME_FTY);
921 enum boot_type_e type = store_get_type();
Bo Lv72d0e902023-01-02 14:27:34 +0000922
923 memset(&avb_ops_, 0, sizeof(AvbOps));
924 avb_ops_.read_from_partition = read_from_partition;
925 avb_ops_.get_preloaded_partition = NULL;
926 avb_ops_.write_to_partition = write_to_partition;
927 avb_ops_.validate_vbmeta_public_key = validate_vbmeta_public_key;
928 avb_ops_.read_rollback_index = read_rollback_index;
929 avb_ops_.write_rollback_index = write_rollback_index;
930 avb_ops_.read_is_device_unlocked = read_is_device_unlocked;
931 avb_ops_.get_unique_guid_for_partition = get_unique_guid_for_partition;
932 avb_ops_.get_size_of_partition = get_size_of_partition;
Matthew Shyuc710a122023-12-14 00:08:41 -0800933 avb_ops_.validate_public_key_for_partition = validate_public_key_for_partition;
Mingyen Hung6e468002023-01-04 23:43:04 -0800934 if (type == BOOT_NAND_MTD || type == BOOT_SNAND || factory_part_num < 0) {
935 avb_ops_.read_persistent_value = NULL;
936 avb_ops_.write_persistent_value = NULL;
937 } else {
938 avb_ops_.read_persistent_value = read_persistent_value;
939 avb_ops_.write_persistent_value = write_persistent_value;
940 }
Bo Lv72d0e902023-01-02 14:27:34 +0000941
942 return 0;
943}
944
945int is_device_unlocked(void)
946{
947 AvbIOResult ret;
948 bool out_is_unlocked;
949
950 ret = read_is_device_unlocked(&avb_ops_, &out_is_unlocked);
951 if (ret == AVB_IO_RESULT_OK)
952 return out_is_unlocked;
953 else
954 return 0;
955}
956
Matthew Shyuc710a122023-12-14 00:08:41 -0800957/* CONFIG_AVB2_RECOVERY is for chaining recovery partition into vbmeta.
958 * This is mainly useful if AVB2 signing is controlled and signed by 3rd party.
959 * For non-AB devices, this should not be set because when update fails, vbmeta
960 * might be in a invalid state and bricks the device.
961 */
Bo Lv72d0e902023-01-02 14:27:34 +0000962int avb_verify(AvbSlotVerifyData** out_data)
963{
964#ifdef CONFIG_AVB2_RECOVERY
965#define RECOVERY "recovery"
966#else
967#define RECOVERY NULL
968#endif
969#ifdef CONFIG_OF_LIBFDT_OVERLAY
970 const char *requested_partitions_ab[AVB_NUM_SLOT + 1] = {"boot", "dtbo",
971 RECOVERY, NULL, NULL};
972#else
973 const char *requested_partitions_ab[AVB_NUM_SLOT + 1] = {"boot", RECOVERY,
974 NULL, NULL, NULL};
975#endif
976 const char *requested_partitions[AVB_NUM_SLOT + 1] = {"boot", "dt",
977 RECOVERY, NULL, NULL};
978 AvbSlotVerifyResult result = AVB_SLOT_VERIFY_RESULT_OK;
979 char *s1 = NULL;
980 char *ab_suffix = NULL;
981 const char *vendor_boot = "vendor_boot";
982 char *vendor_boot_status = NULL;
983 const char **partition_select = requested_partitions;
984 int i = 0;
Mingyen Hung6e468002023-01-04 23:43:04 -0800985 AvbHashtreeErrorMode hashtree_error_mode =
986 AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE;
987 int factory_part_num = get_partition_num_by_name(PART_NAME_FTY);
988 enum boot_type_e type = store_get_type();
Bo Lv72d0e902023-01-02 14:27:34 +0000989
990 s1 = env_get("active_slot");
991 if (!s1) {
992 run_command("get_valid_slot;", 0);
993 s1 = env_get("active_slot");
994 }
995 if (s1) {
996 printf("active_slot is %s\n", s1);
997 if (!strcmp(s1, "normal"))
998 ab_suffix = "";
999 else
1000 ab_suffix = env_get("active_slot");
1001 }
1002
1003 if (!ab_suffix)
1004 ab_suffix = "";
1005 printf("ab_suffix is %s\n", ab_suffix);
1006
1007 if (strcmp(ab_suffix, ""))
1008 partition_select = requested_partitions_ab;
1009
1010 AvbSlotVerifyFlags flags = AVB_SLOT_VERIFY_FLAGS_NONE;
Bo Lv72d0e902023-01-02 14:27:34 +00001011
1012 avb_init();
1013
Bo Lv72d0e902023-01-02 14:27:34 +00001014 vendor_boot_status = env_get("vendor_boot_mode");
1015 if (!strcmp(vendor_boot_status, "true")) {
1016 for (i = 0; i < AVB_NUM_SLOT; i++) {
1017 if (!partition_select[i]) {
1018 partition_select[i] = vendor_boot;
1019 break;
1020 }
1021 }
1022 }
1023
Matthew Shyufcd728f2023-12-07 01:44:32 -08001024 if (is_device_unlocked())
Bo Lv72d0e902023-01-02 14:27:34 +00001025 flags |= AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR;
1026
Matthew Shyuc710a122023-12-14 00:08:41 -08001027#if !CONFIG_IS_ENABLED(AVB2_RECOVERY)
1028 if (!strcmp(ab_suffix, "")) {
1029 printf("recovery: %d\n", run_in_recovery);
1030 if (run_in_recovery) {
1031 flags |= AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION;
1032 memset(requested_partitions, 0, sizeof(requested_partitions));
1033 requested_partitions[0] = "recovery";
1034 }
1035 }
1036#endif
Mingyen Hung6e468002023-01-04 23:43:04 -08001037 if (type == BOOT_NAND_MTD || type == BOOT_SNAND || factory_part_num < 0)
1038 hashtree_error_mode =
1039 AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE;
1040 else
1041 hashtree_error_mode =
1042 AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO;
Matthew Shyuc710a122023-12-14 00:08:41 -08001043
Bo Lv72d0e902023-01-02 14:27:34 +00001044 result = avb_slot_verify(&avb_ops_, partition_select, ab_suffix,
Mingyen Hung6e468002023-01-04 23:43:04 -08001045 flags, hashtree_error_mode, out_data);
Bo Lv72d0e902023-01-02 14:27:34 +00001046
Bo Lv72d0e902023-01-02 14:27:34 +00001047 return result;
1048#undef RECOVERY
1049}
1050
1051static int do_avb_verify(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1052{
1053 AvbSlotVerifyResult result = AVB_SLOT_VERIFY_RESULT_OK;
1054 AvbSlotVerifyData *out_data = NULL;
1055 uint32_t i = 0;
Mingyen Hung6e468002023-01-04 23:43:04 -08001056#if defined(CONFIG_AML_ANTIROLLBACK) || defined(CONFIG_AML_AVB2_ANTIROLLBACK)
1057 uint32_t version = 0;
1058 uint32_t lock_state = 0;
1059#endif
Bo Lv72d0e902023-01-02 14:27:34 +00001060
1061 result = (AvbSlotVerifyResult)avb_verify(&out_data);
1062
1063 printf("result: %d\n", result);
1064 if (result == AVB_SLOT_VERIFY_RESULT_OK && out_data) {
Bo Lv72d0e902023-01-02 14:27:34 +00001065 printf("ab_suffix: %s\n", out_data->ab_suffix);
1066 printf("vbmeta: name: %s, size: %zd, result: %d\n",
1067 out_data->vbmeta_images->partition_name,
1068 out_data->vbmeta_images->vbmeta_size,
1069 out_data->vbmeta_images->verify_result);
1070 printf("num of vbmeta: %zd\n", out_data->num_vbmeta_images);
1071 printf("loaded name: %s, size: %zd, preload: %d\n",
1072 out_data->loaded_partitions->partition_name,
1073 out_data->loaded_partitions->data_size,
1074 out_data->loaded_partitions->preloaded);
1075 printf("num of loaded: %zd\n", out_data->num_loaded_partitions);
1076 printf("cmdline: %s\n", out_data->cmdline);
1077 for (i = 0; i < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; i++)
1078 printf("rollback(%d) = %llu\n", i, out_data->rollback_indexes[i]);
1079
1080#if defined(CONFIG_AML_ANTIROLLBACK) || defined(CONFIG_AML_AVB2_ANTIROLLBACK)
Mingyen Hung6e468002023-01-04 23:43:04 -08001081 if (is_avb_arb_available()) {
1082 for (i = 0; i < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; i++)
1083 if (get_avb_antirollback(i, &version))
1084 printf("rpmb rollback(%d) = %u\n", i, version);
1085 if (get_avb_lock_state(&lock_state))
1086 printf("rpmb lock state: %u\n", lock_state);
1087 }
Bo Lv72d0e902023-01-02 14:27:34 +00001088#endif
1089
1090 avb_slot_verify_data_free(out_data);
1091 }
1092
1093 return result;
1094}
1095
Matthew Shyuc710a122023-12-14 00:08:41 -08001096static int do_avb_verify_memory(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1097{
1098 AvbSlotVerifyResult result = AVB_SLOT_VERIFY_RESULT_OK;
1099 AvbSlotVerifyData *out_data = NULL;
1100 const char *requested_partitions[2] = {NULL, NULL};
1101 char *avb_s = NULL;
1102
1103 if (argc != 3)
1104 return 0;
1105
1106 if (is_device_unlocked())
1107 return CMD_RET_SUCCESS;
1108
1109 run_command("get_avb_mode;", 0);
1110 avb_s = env_get("avb2");
1111 if (!avb_s || !strcmp(avb_s, "0"))
1112 return CMD_RET_SUCCESS;
1113
1114 if (!strcmp(argv[1], "recovery"))
1115 requested_partitions[0] = "recovery-memory";
1116 else
1117 return CMD_RET_FAILURE;
1118
1119 memory_addr = (void *)simple_strtoul(argv[2], NULL, 16);
1120
1121 AvbSlotVerifyFlags flags = AVB_SLOT_VERIFY_FLAGS_NO_VBMETA_PARTITION;
1122
1123 avb_init();
1124 result = avb_slot_verify(&avb_ops_, requested_partitions, "",
1125 flags,
1126 AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, &out_data);
1127
1128 avb_slot_verify_data_free(out_data);
1129
1130 if (result == AVB_SLOT_VERIFY_RESULT_OK)
1131 return CMD_RET_SUCCESS;
1132 else
1133 return CMD_RET_FAILURE;
1134}
1135
1136static int do_avb_recovery(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1137{
1138 char *avb_s = NULL;
1139
1140 run_in_recovery = 0;
1141
1142 if (argc != 2)
1143 return CMD_RET_FAILURE;
1144
1145 if (is_device_unlocked())
1146 return CMD_RET_SUCCESS;
1147
1148 run_command("get_avb_mode;", 0);
1149 avb_s = env_get("avb2");
1150 if (!avb_s || !strcmp(avb_s, "0"))
1151 return CMD_RET_SUCCESS;
1152
1153 if (!strcmp(argv[1], "1"))
1154 run_in_recovery = 1;
1155 else
1156 run_in_recovery = 0;
1157
1158 return CMD_RET_SUCCESS;
1159}
Mingyen Hung6e468002023-01-04 23:43:04 -08001160static int do_avb_persist(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1161{
1162 int result = 0;
1163 uint32_t cmd = 0;
1164
1165 if (argc != 2) {
1166 printf("invalid argc: %d\n", argc);
1167 return -1;
1168 }
1169
1170 avb_init();
1171
1172 if (!strcmp(argv[1], "test")) {
1173 cmd = 0;
1174 } else if (!strcmp(argv[1], "wipe")) {
1175 cmd = 1;
1176 } else if (!strcmp(argv[1], "dump")) {
1177 cmd = 2;
1178 } else {
1179 printf("unknown cmd: %s\n", argv[1]);
1180 return -1;
1181 }
1182
1183 switch (cmd) {
1184 case 0:
1185 printf("persist test\n");
1186 result = persistent_test(&avb_ops_);
1187 break;
1188 case 1:
1189 printf("persist wipe\n");
1190 result = persistent_wipe();
1191 break;
1192 case 2:
1193 printf("persist dump\n");
1194 result = persistent_dump();
1195 break;
1196 }
1197 return result;
1198}
Matthew Shyuc710a122023-12-14 00:08:41 -08001199
Bo Lv72d0e902023-01-02 14:27:34 +00001200uint32_t avb_get_boot_patchlevel_from_vbmeta(AvbSlotVerifyData *data)
1201{
1202 int i, j;
1203 AvbVBMetaData *p;
1204 const char *ret = NULL;
1205 size_t len = 0;
1206 char buff[9];
1207 unsigned long boot_patchlevel;
1208
1209 if (!data)
1210 return 0;
1211
1212 for (i = 0; i < data->num_vbmeta_images; i++) {
1213 p = &data->vbmeta_images[i];
1214 if (strcmp(p->partition_name, "vbmeta") == 0) { /* match */
1215 if (p->verify_result != AVB_VBMETA_VERIFY_RESULT_OK) {
1216 // not verified
1217 printf("vbmeta verify_result %d\n", p->verify_result);
1218
1219 /*device lock, treat as error*/
1220 if (!is_device_unlocked()) {
1221 printf("device lock, but vbmeta verify fail\n");
1222 return 0;
1223 }
1224 }
1225
1226 ret = avb_property_lookup(p->vbmeta_data,
1227 p->vbmeta_size,
Mingyen Hung6e468002023-01-04 23:43:04 -08001228 "com.android.build.init_boot.security_patch",
1229 0,
1230 &len);
1231 if (ret)
1232 break;
1233
1234 ret = avb_property_lookup(p->vbmeta_data,
1235 p->vbmeta_size,
Bo Lv72d0e902023-01-02 14:27:34 +00001236 "com.android.build.boot.security_patch",
1237 0,
1238 &len);
Bo Lv72d0e902023-01-02 14:27:34 +00001239 if (ret)
1240 break;
Mingyen Hung6e468002023-01-04 23:43:04 -08001241
Bo Lv72d0e902023-01-02 14:27:34 +00001242// else
1243// printf("not found com.android.build.boot.
1244// security_patch,len = %d\n", (int)len);
1245 }
1246 }
1247
1248 if (ret) {
1249 for (i = 0, j = 0; i < len; i++) {
1250 if (ret[i] != '-' && j < 8)
1251 buff[j++] = ret[i];
1252 }
1253 buff[8] = '\0';
1254 if (!strict_strtoul(buff, 10, &boot_patchlevel))
1255 return (uint32_t)boot_patchlevel;
1256 }
1257
1258 return 0;
1259}
1260
1261static cmd_tbl_t cmd_avb_sub[] = {
Mingyen Hung6e468002023-01-04 23:43:04 -08001262 U_BOOT_CMD_MKENT(verify, 0, 0, do_avb_verify, "", ""),
1263 U_BOOT_CMD_MKENT(persist, 2, 0, do_avb_persist, "avb persist test/wipe/dump",
1264 "avb persist test/wipe/dump"),
Matthew Shyuc710a122023-12-14 00:08:41 -08001265 U_BOOT_CMD_MKENT(memory, 4, 0, do_avb_verify_memory, "", ""),
1266 U_BOOT_CMD_MKENT(recovery, 2, 0, do_avb_recovery, "", ""),
Bo Lv72d0e902023-01-02 14:27:34 +00001267};
1268
1269static int do_avb_ops(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1270{
1271 cmd_tbl_t *c;
Matthew Shyuc710a122023-12-14 00:08:41 -08001272 int ret = CMD_RET_SUCCESS;
Bo Lv72d0e902023-01-02 14:27:34 +00001273
Mingyen Hung6e468002023-01-04 23:43:04 -08001274 /* Strip off leading 'avb' command argument */
Bo Lv72d0e902023-01-02 14:27:34 +00001275 argc--;
1276 argv++;
1277
1278 c = find_cmd_tbl(argv[0], &cmd_avb_sub[0], ARRAY_SIZE(cmd_avb_sub));
1279
1280 if (c) {
1281 ret = c->cmd(cmdtp, flag, argc, argv);
1282 } else {
1283 cmd_usage(cmdtp);
Matthew Shyuc710a122023-12-14 00:08:41 -08001284 ret = CMD_RET_FAILURE;
Bo Lv72d0e902023-01-02 14:27:34 +00001285 }
1286
1287 return ret;
1288}
1289
1290
1291U_BOOT_CMD(
Matthew Shyuc710a122023-12-14 00:08:41 -08001292 avb, 4, 0, do_avb_ops,
Bo Lv72d0e902023-01-02 14:27:34 +00001293 "avb",
1294 "\nThis command will trigger related avb operations\n"
1295 );