xref: /rk3399_rockchip-uboot/lib/avb/rk_avb_user/rk_avb_ops_user.c (revision f4e1db9544a8994a69fe47e63f7735939641bbe4)
1 /*
2  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <image.h>
9 #include <android_image.h>
10 #include <malloc.h>
11 #include <mapmem.h>
12 #include <errno.h>
13 #include <command.h>
14 #include <mmc.h>
15 #include <blk.h>
16 #include <part.h>
17 #include <android_avb/avb_ops_user.h>
18 #include <android_avb/libavb_ab.h>
19 #include <android_avb/avb_atx_validate.h>
20 #include <android_avb/avb_atx_types.h>
21 #include <optee_include/OpteeClientInterface.h>
22 #include <optee_include/tee_api_defines.h>
23 #include <android_avb/avb_vbmeta_image.h>
24 #include <android_avb/avb_atx_validate.h>
25 #include <android_avb/rk_avb_ops_user.h>
26 #include <boot_rkimg.h>
27 
28 /* rk used */
29 int rk_avb_read_slot_count(char *slot_count)
30 {
31 	*slot_count = SLOT_NUM;
32 
33 	return 0;
34 }
35 
36 int rk_avb_read_slot_suffixes(char *slot_suffixes)
37 {
38 	memcpy(slot_suffixes, CURR_SYSTEM_SLOT_SUFFIX,
39 	       strlen(CURR_SYSTEM_SLOT_SUFFIX));
40 
41 	return 0;
42 }
43 
44 int rk_avb_set_slot_active(unsigned int *slot_number)
45 {
46 	AvbOps* ops;
47 	ops = avb_ops_user_new();
48 	int ret = 0;
49 
50 	if (ops == NULL) {
51 		printf("avb_ops_user_new() failed!\n");
52 		return -1;
53 	}
54 
55 	debug("set_slot_active\n");
56 	if (avb_ab_mark_slot_active(ops->ab_ops, *slot_number) != 0) {
57 		printf("set_slot_active error!\n");
58 		ret = -1;
59 	}
60 
61 	avb_ops_user_free(ops);
62 	return ret;
63 }
64 
65 static bool slot_is_bootable(AvbABSlotData* slot) {
66 	return (slot->priority > 0) &&
67 	       (slot->successful_boot || (slot->tries_remaining > 0));
68 }
69 
70 AvbABFlowResult rk_avb_ab_slot_select(AvbABOps* ab_ops,char* select_slot)
71 {
72 	AvbABFlowResult ret = AVB_AB_FLOW_RESULT_OK;
73 	AvbIOResult io_ret = AVB_IO_RESULT_OK;
74 	AvbABData ab_data;
75 	size_t slot_index_to_boot;
76 
77 	io_ret = ab_ops->read_ab_metadata(ab_ops, &ab_data);
78 	if (io_ret != AVB_IO_RESULT_OK) {
79 		avb_error("I/O error while loading A/B metadata.\n");
80 		ret = AVB_AB_FLOW_RESULT_ERROR_IO;
81 		goto out;
82 	}
83 	if (slot_is_bootable(&ab_data.slots[0]) && slot_is_bootable(&ab_data.slots[1])) {
84 		if (ab_data.slots[1].priority > ab_data.slots[0].priority) {
85 			slot_index_to_boot = 1;
86 		} else {
87 			slot_index_to_boot = 0;
88 		}
89 	} else if(slot_is_bootable(&ab_data.slots[0])) {
90 		slot_index_to_boot = 0;
91 	} else if(slot_is_bootable(&ab_data.slots[1])) {
92 		slot_index_to_boot = 1;
93 	} else {
94 		avb_error("No bootable slots found.\n");
95 		ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;
96 		goto out;
97 	}
98 
99 	if (slot_index_to_boot == 0) {
100 		strcpy(select_slot, "_a");
101 	} else if(slot_index_to_boot == 1) {
102 		strcpy(select_slot, "_b");
103 	}
104 out:
105 	return ret;
106 }
107 
108 int rk_avb_get_current_slot(char *select_slot)
109 {
110 	AvbOps* ops;
111 	int ret = 0;
112 
113 	ops = avb_ops_user_new();
114 	if (ops == NULL) {
115 		printf("avb_ops_user_new() failed!\n");
116 		return -1;
117 	}
118 
119 	if (rk_avb_ab_slot_select(ops->ab_ops, select_slot) != 0) {
120 		printf("###There is no bootable slot, bring up last_boot!###\n");
121 		if (rk_get_lastboot() == 1)
122 			memcpy(select_slot, "_b", 2);
123 		else if(rk_get_lastboot() == 0)
124 			memcpy(select_slot, "_a", 2);
125 		else
126 			return -1;
127 		ret = 0;
128 	}
129 
130 	avb_ops_user_free(ops);
131 	return ret;
132 }
133 
134 int rk_avb_read_permanent_attributes(uint8_t *attributes, uint32_t size)
135 {
136 #ifdef CONFIG_OPTEE_CLIENT
137 	if(trusty_read_permanent_attributes(attributes, size) != 0) {
138 		printf("trusty_read_permanent_attributes failed!\n");
139 		return -1;
140 	}
141 
142 	return 0;
143 #else
144 	return -1;
145 #endif
146 }
147 
148 int rk_avb_write_permanent_attributes(uint8_t *attributes, uint32_t size)
149 {
150 #ifdef CONFIG_OPTEE_CLIENT
151 	if(trusty_write_permanent_attributes(attributes, size) != 0) {
152 		printf("trusty_write_permanent_attributes failed!\n");
153 		return -1;
154 	}
155 
156 	return 0;
157 #else
158 	return -1;
159 #endif
160 }
161 
162 int rk_avb_read_flash_lock_state(uint8_t *flash_lock_state)
163 {
164 #ifdef CONFIG_OPTEE_CLIENT
165 	int ret;
166 
167 	ret = trusty_read_flash_lock_state(flash_lock_state);
168 	switch (ret) {
169 	case TEE_SUCCESS:
170 		break;
171 	case TEE_ERROR_GENERIC:
172 	case TEE_ERROR_NO_DATA:
173 	case TEE_ERROR_ITEM_NOT_FOUND:
174 		*flash_lock_state = 1;
175 		if (trusty_write_flash_lock_state(*flash_lock_state)) {
176 			avb_error("trusty_write_flash_lock_state error!");
177 			ret = -1;
178 		} else {
179 			ret = trusty_read_flash_lock_state(flash_lock_state);
180 		}
181 		break;
182 	default:
183 		printf("%s: trusty_read_flash_lock_state failed\n", __FILE__);
184 	}
185 
186 	return ret;
187 #else
188 	return -1;
189 #endif
190 }
191 
192 int rk_avb_write_flash_lock_state(uint8_t flash_lock_state)
193 {
194 #ifdef CONFIG_OPTEE_CLIENT
195 	if (trusty_write_flash_lock_state(flash_lock_state)) {
196 		printf("trusty_write_flash_lock_state error!\n");
197 		return -1;
198 	}
199 
200 	return 0;
201 #else
202 	return -1;
203 #endif
204 }
205 
206 int rk_avb_write_lock_state(uint8_t lock_state)
207 {
208 #ifdef CONFIG_OPTEE_CLIENT
209 	if (trusty_write_lock_state(lock_state)) {
210 		printf("trusty_write_lock_state error!\n");
211 		return -1;
212 	}
213 
214 	return 0;
215 #else
216 	return -1;
217 #endif
218 }
219 
220 int rk_avb_read_lock_state(uint8_t *lock_state)
221 {
222 #ifdef CONFIG_OPTEE_CLIENT
223 	int ret;
224 
225 	ret = trusty_read_lock_state(lock_state);
226 	switch (ret) {
227 	case TEE_SUCCESS:
228 		break;
229 	case TEE_ERROR_GENERIC:
230 	case TEE_ERROR_NO_DATA:
231 	case TEE_ERROR_ITEM_NOT_FOUND:
232 		*lock_state = 1;
233 		if (rk_avb_write_lock_state(*lock_state)) {
234 			avb_error("avb_write_lock_state error!");
235 			ret = -1;
236 		} else {
237 			ret = trusty_read_lock_state(lock_state);
238 		}
239 		break;
240 	default:
241 		printf("%s: trusty_read_lock_state failed\n", __FILE__);
242 	}
243 
244 	return ret;
245 #else
246 	return -1;
247 #endif
248 }
249 
250 int rk_avb_write_perm_attr_flag(uint8_t flag)
251 {
252 #ifdef CONFIG_OPTEE_CLIENT
253 	if (trusty_write_permanent_attributes_flag(flag)) {
254 		printf("trusty_write_permanent_attributes_flag error!\n");
255 		return -1;
256 	}
257 
258 	return 0;
259 #else
260 	return -1;
261 #endif
262 }
263 
264 int rk_avb_read_perm_attr_flag(uint8_t *flag)
265 {
266 #ifdef CONFIG_OPTEE_CLIENT
267 	int ret;
268 
269 	ret = trusty_read_permanent_attributes_flag(flag);
270 	switch (ret) {
271 	case TEE_SUCCESS:
272 		break;
273 	case TEE_ERROR_GENERIC:
274 	case TEE_ERROR_NO_DATA:
275 	case TEE_ERROR_ITEM_NOT_FOUND:
276 		*flag = 0;
277 		if (rk_avb_write_perm_attr_flag(*flag)) {
278 			avb_error("avb_write_perm_attr_flag error!");
279 			ret = -1;
280 		} else {
281 			ret = trusty_read_permanent_attributes_flag(flag);
282 		}
283 		break;
284 	default:
285 		printf("%s: trusty_read_permanent_attributes_flag failed",
286 		       __FILE__);
287 	}
288 
289 	return ret;
290 #else
291 	return -1;
292 #endif
293 }
294 
295 int rk_avb_read_vbootkey_hash(uint8_t *buf, uint8_t length)
296 {
297 #ifdef CONFIG_OPTEE_CLIENT
298 	if (trusty_read_vbootkey_hash((uint32_t *)buf,
299 				      (uint32_t)length / sizeof(uint32_t))) {
300 		printf("trusty_read_vbootkey_hash error!\n");
301 		return -1;
302 	}
303 
304 	return 0;
305 #else
306 	return -1;
307 #endif
308 }
309 
310 int rk_avb_write_vbootkey_hash(uint8_t *buf, uint8_t length)
311 {
312 #ifdef CONFIG_OPTEE_CLIENT
313 	if (trusty_write_vbootkey_hash((uint32_t *)buf,
314 				       (uint32_t)length / sizeof(uint32_t))) {
315 		printf("trusty_write_vbootkey_hash error!\n");
316 		return -1;
317 	}
318 
319 	return 0;
320 #else
321 	return -1;
322 #endif
323 }
324 
325 int rk_avb_close_optee_client(void)
326 {
327 #ifdef CONFIG_OPTEE_CLIENT
328 	if(trusty_notify_optee_uboot_end()) {
329 		printf("trusty_notify_optee_uboot_end error!\n");
330 		return -1;
331 	}
332 
333 	return 0;
334 #else
335 	return -1;
336 #endif
337 }
338 
339 int rk_avb_read_attribute_hash(uint8_t *buf, uint8_t length)
340 {
341 #ifdef CONFIG_OPTEE_CLIENT
342 	if (trusty_read_attribute_hash((uint32_t *)buf,
343 	    (uint32_t)(length/sizeof(uint32_t)))) {
344 		printf("trusty_read_attribute_hash error!\n");
345 		return -1;
346 	}
347 
348 	return 0;
349 #else
350 	return -1;
351 #endif
352 }
353 
354 int rk_avb_write_attribute_hash(uint8_t *buf, uint8_t length)
355 {
356 #ifdef CONFIG_OPTEE_CLIENT
357 	if (trusty_write_attribute_hash((uint32_t *)buf,
358 	    (uint32_t)(length/sizeof(uint32_t)))) {
359 		printf("trusty_write_attribute_hash error!\n");
360 		return -1;
361 	}
362 
363 	return 0;
364 #else
365 	return -1;
366 #endif
367 }
368 
369 int rk_avb_read_all_rollback_index(char *buffer)
370 {
371 	AvbOps* ops;
372 	uint64_t stored_rollback_index = 0;
373 	AvbIOResult io_ret;
374 	char temp[ROLLBACK_MAX_SIZE] = {0};
375 	int n;
376 
377 	ops = avb_ops_user_new();
378 	if (ops == NULL) {
379 		printf("avb_ops_user_new() failed!\n");
380 		return -1;
381 	}
382 
383 	for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) {
384 		io_ret = ops->read_rollback_index(
385 			ops, n, &stored_rollback_index);
386 		if (io_ret != AVB_IO_RESULT_OK)
387 			goto out;
388 		snprintf(temp, sizeof(int) + 1, "%d", n);
389 		strncat(buffer, temp, ROLLBACK_MAX_SIZE);
390 		strncat(buffer, ":", 1);
391 		snprintf(temp, sizeof(uint64_t) + 1, "%lld",
392 			 stored_rollback_index);
393 		strncat(buffer, temp, ROLLBACK_MAX_SIZE);
394 		strncat(buffer, ",", 1);
395 	}
396 
397 	io_ret =
398 		ops->read_rollback_index(ops,
399 					 AVB_ATX_PIK_VERSION_LOCATION,
400 					 &stored_rollback_index);
401 	if (io_ret != AVB_IO_RESULT_OK) {
402 		avb_error("Failed to read PIK minimum version.\n");
403 		goto out;
404 	}
405 	/* PIK rollback index */
406 	snprintf(temp, sizeof(int) + 1, "%d", AVB_ATX_PIK_VERSION_LOCATION);
407 	strncat(buffer, temp, ROLLBACK_MAX_SIZE);
408 	strncat(buffer, ":", 1);
409 	snprintf(temp, sizeof(uint64_t) + 1, "%lld", stored_rollback_index);
410 	strncat(buffer, temp, ROLLBACK_MAX_SIZE);
411 	strncat(buffer, ",", 1);
412 	io_ret = ops->read_rollback_index(ops,
413 					  AVB_ATX_PSK_VERSION_LOCATION,
414 					  &stored_rollback_index);
415 	if (io_ret != AVB_IO_RESULT_OK) {
416 		avb_error("Failed to read PSK minimum version.\n");
417 		goto out;
418 	}
419 	/* PSK rollback index */
420 	snprintf(temp, sizeof(int) + 1, "%d", AVB_ATX_PSK_VERSION_LOCATION);
421 	strncat(buffer, temp, ROLLBACK_MAX_SIZE);
422 	strncat(buffer, ":", 1);
423 	snprintf(temp, sizeof(uint64_t) + 1, "%lld", stored_rollback_index);
424 	strncat(buffer, temp, ROLLBACK_MAX_SIZE);
425 	debug("%s\n", buffer);
426 	avb_ops_user_free(ops);
427 
428 	return 0;
429 out:
430 	avb_ops_user_free(ops);
431 
432 	return -1;
433 }
434 
435 int rk_avb_read_bootloader_locked_flag(uint8_t *flag)
436 {
437 #ifdef CONFIG_OPTEE_CLIENT
438 	if (trusty_read_vbootkey_enable_flag(flag)) {
439 		return -1;
440 	}
441 	return 0;
442 #else
443 	return -1;
444 #endif
445 }
446 
447 #ifdef CONFIG_SUPPORT_EMMC_RPMB
448 static int curr_device = -1;
449 
450 int rk_bootloader_rollback_index_read(uint32_t offset, uint32_t bytes,
451 				      void *rb_index)
452 {
453 
454 	struct mmc *mmc;
455 	uint8_t rpmb_buf[256] = {0};
456 	uint32_t n;
457 	char original_part;
458 
459 	if ((offset + bytes) > 256)
460 		return -1;
461 
462 	if (curr_device < 0) {
463 		if (get_mmc_num() > 0)
464 			curr_device = 0;
465 		else {
466 			avb_error("No MMC device available");
467 			return -1;
468 		}
469 	}
470 
471 	mmc = find_mmc_device(curr_device);
472 	/* Switch to the RPMB partition */
473 #ifndef CONFIG_BLK
474 	original_part = mmc->block_dev.hwpart;
475 #else
476 	original_part = mmc_get_blk_desc(mmc)->hwpart;
477 #endif
478 	if (blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, MMC_PART_RPMB) !=
479 	    0)
480 		return -1;
481 
482 	n =  mmc_rpmb_read(mmc, rpmb_buf, RPMB_BASE_ADDR, 1, NULL);
483 	if (n != 1)
484 		return -1;
485 
486 	/* Return to original partition */
487 	if (blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, original_part) !=
488 	    0)
489 		return -1;
490 
491 	memcpy(rb_index, (void*)&rpmb_buf[offset], bytes);
492 
493 	return 0;
494 }
495 
496 int rk_avb_get_bootloader_min_version(char *buffer)
497 {
498 	uint32_t rb_index;
499 	char temp[ROLLBACK_MAX_SIZE] = {0};
500 
501 	if (rk_bootloader_rollback_index_read(UBOOT_RB_INDEX_OFFSET,
502 					      sizeof(uint32_t), &rb_index)) {
503 		avb_error("Can not read uboot rollback index");
504 		return -1;
505 	}
506 	snprintf(temp, sizeof(int) + 1, "%d", 0);
507 	strncat(buffer, temp, ROLLBACK_MAX_SIZE);
508 	strncat(buffer, ":", 1);
509 	snprintf(temp, sizeof(uint32_t) + 1, "%d", rb_index);
510 	strncat(buffer, temp, ROLLBACK_MAX_SIZE);
511 	strncat(buffer, ",", 1);
512 
513 	if (rk_bootloader_rollback_index_read(TRUST_RB_INDEX_OFFSET,
514 					      sizeof(uint32_t), &rb_index)) {
515 		avb_error("Can not read trust rollback index");
516 		return -1;
517 	}
518 
519 	snprintf(temp, sizeof(int) + 1, "%d", 1);
520 	strncat(buffer, temp, ROLLBACK_MAX_SIZE);
521 	strncat(buffer, ":", 1);
522 	snprintf(temp, sizeof(uint32_t) + 1, "%d", rb_index);
523 	strncat(buffer, temp, ROLLBACK_MAX_SIZE);
524 
525 	return 0;
526 }
527 #endif
528 
529 void rk_avb_get_at_vboot_state(char *buf)
530 {
531 	char temp_flag = 0;
532 	char *lock_val = NULL;
533 	char *unlock_dis_val = NULL;
534 	char *perm_attr_flag = NULL;
535 	char *bootloader_locked_flag = NULL;
536 	char *rollback_indices;
537 	char min_versions[ROLLBACK_MAX_SIZE + 1] = {0};
538 	int n;
539 
540 	if (rk_avb_read_perm_attr_flag((uint8_t *)&temp_flag)) {
541 		avb_error("Can not read perm_attr_flag!");
542 		perm_attr_flag = "";
543 	} else {
544 		perm_attr_flag = temp_flag ? "1" : "0";
545 	}
546 
547 	temp_flag = 0;
548 	if (rk_avb_read_lock_state((uint8_t *)&temp_flag)) {
549 		avb_error("Can not read lock state!");
550 		lock_val = "";
551 		unlock_dis_val = "";
552 	} else {
553 		lock_val = (temp_flag & LOCK_MASK) ? "0" : "1";
554 		unlock_dis_val = (temp_flag & UNLOCK_DISABLE_MASK) ? "1" : "0";
555 	}
556 
557 	temp_flag = 0;
558 	if (rk_avb_read_bootloader_locked_flag((uint8_t *)&temp_flag)) {
559 		avb_error("Can not read bootloader locked flag!");
560 		bootloader_locked_flag = "";
561 	} else {
562 		bootloader_locked_flag = temp_flag ? "1" : "0";
563 	}
564 
565 	rollback_indices = malloc(VBOOT_STATE_SIZE);
566 	if (!rollback_indices) {
567 		avb_error("No buff to malloc!");
568 		return;
569 	}
570 
571 	memset(rollback_indices, 0, VBOOT_STATE_SIZE);
572 	if (rk_avb_read_all_rollback_index(rollback_indices))
573 		avb_error("Can not read avb_min_ver!");
574 
575 	/* bootloader-min-versions */
576 	if (rk_avb_get_bootloader_min_version(min_versions))
577 		avb_error("Call rk_avb_get_bootloader_min_version error!");
578 
579 	n = snprintf(buf, VBOOT_STATE_SIZE - 1,
580 		     "avb-perm-attr-set=%s\n"
581 		     "avb-locked=%s\n"
582 		     "avb-unlock-disabled=%s\n"
583 		     "bootloader-locked=%s\n"
584 		     "avb-min-versions=%s\n"
585 		     "bootloader-min-versions=%s\n",
586 		     perm_attr_flag,
587 		     lock_val,
588 		     unlock_dis_val,
589 		     bootloader_locked_flag,
590 		     rollback_indices,
591 		     min_versions);
592 	if (n >= VBOOT_STATE_SIZE) {
593 		avb_error("The VBOOT_STATE buf is truncated\n");
594 		buf[VBOOT_STATE_SIZE - 1] = 0;
595 	}
596 	debug("The vboot state buf is %s\n", buf);
597 	free(rollback_indices);
598 }
599 
600 int rk_avb_get_ab_info(AvbABData* ab_data)
601 {
602 	AvbOps* ops;
603 	AvbIOResult io_ret = AVB_IO_RESULT_OK;
604 	int ret = 0;
605 
606 	ops = avb_ops_user_new();
607 	if (ops == NULL) {
608 		printf("%s: avb_ops_user_new() failed!\n", __FILE__);
609 		return -1;
610 	}
611 
612 	io_ret = ops->ab_ops->read_ab_metadata(ops->ab_ops, ab_data);
613 	if (io_ret != AVB_IO_RESULT_OK) {
614 		avb_error("I/O error while loading A/B metadata.\n");
615 		ret = -1;
616 	}
617 
618 	avb_ops_user_free(ops);
619 
620 	return ret;
621 }
622 
623 int rk_avb_get_part_has_slot_info(const char *base_name)
624 {
625 	char *part_name;
626 	int part_num;
627 	size_t part_name_len;
628 	disk_partition_t part_info;
629 	struct blk_desc *dev_desc;
630 	const char *slot_suffix = "_a";
631 
632 	dev_desc = rockchip_get_bootdev();
633 	if (!dev_desc) {
634 		printf("%s: Could not find device!\n", __func__);
635 		return -1;
636 	}
637 
638 	if (base_name == NULL) {
639 		printf("The base_name is NULL!\n");
640 		return -1;
641 	}
642 
643 	part_name_len = strlen(base_name) + 1;
644 	part_name_len += strlen(slot_suffix);
645 	part_name = malloc(part_name_len);
646 	if (!part_name) {
647 		printf("%s can not malloc a buffer!\n", __FILE__);
648 		return -1;
649 	}
650 
651 	memset(part_name, 0, part_name_len);
652 	snprintf(part_name, part_name_len, "%s%s", base_name, slot_suffix);
653 	part_num = part_get_info_by_name(dev_desc, part_name, &part_info);
654 	if (part_num < 0) {
655 		printf("Could not find partition \"%s\"\n", part_name);
656 		part_num = -1;
657 	}
658 
659 	free(part_name);
660 	return part_num;
661 }
662 
663 int rk_auth_unlock(void *buffer, char *out_is_trusted)
664 {
665 	AvbOps* ops;
666 
667 	ops = avb_ops_user_new();
668 	if (ops == NULL) {
669 		avb_error("avb_ops_user_new() failed!");
670 		return -1;
671 	}
672 
673 	if (avb_atx_validate_unlock_credential(ops->atx_ops,
674 					   (AvbAtxUnlockCredential*)buffer,
675 					   (bool*)out_is_trusted)) {
676 		avb_ops_user_free(ops);
677 		return -1;
678 	}
679 	avb_ops_user_free(ops);
680 	if (*out_is_trusted == true)
681 		return 0;
682 	else
683 		return -1;
684 }
685 
686 int rk_generate_unlock_challenge(void *buffer, uint32_t *challenge_len)
687 {
688 	AvbOps* ops;
689 	AvbIOResult result = AVB_IO_RESULT_OK;
690 
691 	ops = avb_ops_user_new();
692 	if (ops == NULL) {
693 		avb_error("avb_ops_user_new() failed!");
694 		return -1;
695 	}
696 
697 	result = avb_atx_generate_unlock_challenge(ops->atx_ops,
698 						   (AvbAtxUnlockChallenge *)buffer);
699 	avb_ops_user_free(ops);
700 	*challenge_len = sizeof(AvbAtxUnlockChallenge);
701 	if (result == AVB_IO_RESULT_OK)
702 		return 0;
703 	else
704 		return -1;
705 }
706 
707 int rk_get_lastboot(void)
708 {
709 
710 	AvbIOResult io_ret = AVB_IO_RESULT_OK;
711 	AvbABData ab_data;
712 	int lastboot = -1;
713 	AvbOps* ops;
714 
715 	ops = avb_ops_user_new();
716 	if (ops == NULL) {
717 		printf("avb_ops_user_new() failed!\n");
718 		return -1;
719 	}
720 
721 	io_ret = ops->ab_ops->read_ab_metadata(ops->ab_ops, &ab_data);
722 	if (io_ret != AVB_IO_RESULT_OK) {
723 		avb_error("I/O error while loading A/B metadata.\n");
724 		goto out;
725 	}
726 
727 	lastboot = ab_data.last_boot;
728 out:
729 	avb_ops_user_free(ops);
730 
731 	return lastboot;
732 }
733