xref: /rk3399_rockchip-uboot/lib/avb/rk_avb_user/rk_avb_ops_user.c (revision 459bc93392ed13d7d5ee9fe03bb3e4dab27f6ce4)
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("get_current_slot error!\n");
121 		ret = -1;
122 	}
123 
124 	avb_ops_user_free(ops);
125 	return ret;
126 }
127 
128 int rk_avb_read_permanent_attributes(uint8_t *attributes, uint32_t size)
129 {
130 #ifdef CONFIG_OPTEE_CLIENT
131 	if(trusty_read_permanent_attributes(attributes, size) != 0) {
132 		printf("trusty_read_permanent_attributes failed!\n");
133 		return -1;
134 	}
135 
136 	return 0;
137 #else
138 	return -1;
139 #endif
140 }
141 
142 int rk_avb_write_permanent_attributes(uint8_t *attributes, uint32_t size)
143 {
144 #ifdef CONFIG_OPTEE_CLIENT
145 	if(trusty_write_permanent_attributes(attributes, size) != 0) {
146 		printf("trusty_write_permanent_attributes failed!\n");
147 		return -1;
148 	}
149 
150 	return 0;
151 #else
152 	return -1;
153 #endif
154 }
155 
156 int rk_avb_read_flash_lock_state(uint8_t *flash_lock_state)
157 {
158 #ifdef CONFIG_OPTEE_CLIENT
159 	int ret;
160 
161 	ret = trusty_read_flash_lock_state(flash_lock_state);
162 	if (ret == TEE_ERROR_GENERIC) {
163 		*flash_lock_state = 1;
164 		if (trusty_write_flash_lock_state(*flash_lock_state)) {
165 			printf("trusty_write_flash_lock_state error!\n");
166 			return -1;
167 		}
168 
169 		ret = trusty_read_flash_lock_state(flash_lock_state);
170 		if (ret == 0)
171 			return 0;
172 	} else if (ret == 0) {
173 		return 0;
174 	} else {
175 		printf("avb_read_flash_lock_state ret = %x\n", ret);
176 		return -1;
177 	}
178 #else
179 	return -1;
180 #endif
181 }
182 
183 int rk_avb_write_flash_lock_state(uint8_t flash_lock_state)
184 {
185 #ifdef CONFIG_OPTEE_CLIENT
186 	if (trusty_write_flash_lock_state(flash_lock_state)) {
187 		printf("trusty_write_flash_lock_state error!\n");
188 		return -1;
189 	}
190 
191 	return 0;
192 #else
193 	return -1;
194 #endif
195 }
196 
197 int rk_avb_write_lock_state(uint8_t lock_state)
198 {
199 #ifdef CONFIG_OPTEE_CLIENT
200 	if (trusty_write_lock_state(lock_state)) {
201 		printf("trusty_write_lock_state error!\n");
202 		return -1;
203 	}
204 
205 	return 0;
206 #else
207 	return -1;
208 #endif
209 }
210 
211 int rk_avb_read_lock_state(uint8_t *lock_state)
212 {
213 #ifdef CONFIG_OPTEE_CLIENT
214 	int ret;
215 
216 	ret = trusty_read_lock_state(lock_state);
217 	if (ret == TEE_ERROR_GENERIC) {
218 		*lock_state = 1;
219 		if (rk_avb_write_lock_state(*lock_state)) {
220 			printf("avb_write_lock_state error!\n");
221 			return -1;
222 		}
223 
224 		ret = trusty_read_lock_state(lock_state);
225 		if (ret == 0)
226 			return 0;
227 	} else if (ret == 0) {
228 		return 0;
229 	} else {
230 		printf("avb_read_lock_state ret = %x\n", ret);
231 		return -1;
232 	}
233 #else
234 	return -1;
235 #endif
236 }
237 
238 int rk_avb_write_perm_attr_flag(uint8_t flag)
239 {
240 #ifdef CONFIG_OPTEE_CLIENT
241 	if (trusty_write_permanent_attributes_flag(flag)) {
242 		printf("trusty_write_permanent_attributes_flag error!\n");
243 		return -1;
244 	}
245 
246 	return 0;
247 #else
248 	return -1;
249 #endif
250 }
251 
252 int rk_avb_read_perm_attr_flag(uint8_t *flag)
253 {
254 #ifdef CONFIG_OPTEE_CLIENT
255 	int ret;
256 
257 	ret = trusty_read_permanent_attributes_flag(flag);
258 	if (ret != TEE_SUCCESS) {
259 		*flag = 0;
260 		if (rk_avb_write_perm_attr_flag(*flag)) {
261 			printf("avb_write_perm_attr_flag error!\n");
262 			return -1;
263 		}
264 
265 		ret = trusty_read_permanent_attributes_flag(flag);
266 		if (ret == 0)
267 			return 0;
268 	} else if (ret == 0) {
269 		return 0;
270 	} else {
271 		printf("avb_read_perm_attr_flag ret = %x\n", ret);
272 		return -1;
273 	}
274 #else
275 	return -1;
276 #endif
277 }
278 
279 int rk_avb_read_vbootkey_hash(uint8_t *buf, uint8_t length)
280 {
281 #ifdef CONFIG_OPTEE_CLIENT
282 	if (trusty_read_vbootkey_hash((uint32_t *)buf,
283 				      (uint32_t)length / sizeof(uint32_t))) {
284 		printf("trusty_read_vbootkey_hash error!\n");
285 		return -1;
286 	}
287 
288 	return 0;
289 #else
290 	return -1;
291 #endif
292 }
293 
294 int rk_avb_write_vbootkey_hash(uint8_t *buf, uint8_t length)
295 {
296 #ifdef CONFIG_OPTEE_CLIENT
297 	if (trusty_write_vbootkey_hash((uint32_t *)buf,
298 				       (uint32_t)length / sizeof(uint32_t))) {
299 		printf("trusty_write_vbootkey_hash error!\n");
300 		return -1;
301 	}
302 
303 	return 0;
304 #else
305 	return -1;
306 #endif
307 }
308 
309 int rk_avb_close_optee_client(void)
310 {
311 #ifdef CONFIG_OPTEE_CLIENT
312 	if(trusty_notify_optee_uboot_end()) {
313 		printf("trusty_notify_optee_uboot_end error!\n");
314 		return -1;
315 	}
316 
317 	return 0;
318 #else
319 	return -1;
320 #endif
321 }
322 
323 int rk_avb_read_attribute_hash(uint8_t *buf, uint8_t length)
324 {
325 #ifdef CONFIG_OPTEE_CLIENT
326 	if (trusty_read_attribute_hash((uint32_t *)buf,
327 	    (uint32_t)(length/sizeof(uint32_t)))) {
328 		printf("trusty_read_attribute_hash error!\n");
329 		return -1;
330 	}
331 
332 	return 0;
333 #else
334 	return -1;
335 #endif
336 }
337 
338 int rk_avb_write_attribute_hash(uint8_t *buf, uint8_t length)
339 {
340 #ifdef CONFIG_OPTEE_CLIENT
341 	if (trusty_write_attribute_hash((uint32_t *)buf,
342 	    (uint32_t)(length/sizeof(uint32_t)))) {
343 		printf("trusty_write_attribute_hash error!\n");
344 		return -1;
345 	}
346 
347 	return 0;
348 #else
349 	return -1;
350 #endif
351 }
352 
353 static const char* slot_suffixes[2] = {"_a", "_b"};
354 
355 int rk_avb_read_all_rollback_index(char *buffer)
356 {
357 	AvbOps* ops;
358 	AvbVBMetaImageHeader vbmeta_header;
359 	uint64_t stored_rollback_index = 0;
360 	uint64_t pik_rollback_index = 0;
361 	uint64_t psk_rollback_index = 0;
362 	AvbSlotVerifyFlags flags;
363 	AvbIOResult io_ret;
364 	char temp[ROLLBACK_MAX_SIZE] = {0};
365 	AvbAtxPublicKeyMetadata *metadata;
366 	int n;
367 	bool unlocked;
368 	AvbSlotVerifyResult verify_result;
369 	AvbSlotVerifyData *slot_data[SLOT_NUM] = {NULL, NULL};
370 	const char *requested_partitions[1] = {"vbmeta"};
371 
372 	ops = avb_ops_user_new();
373 	if (ops == NULL) {
374 		printf("avb_ops_user_new() failed!\n");
375 		return -1;
376 	}
377 
378 	if (ops->read_is_device_unlocked(ops, &unlocked) != 0) {
379 		printf("Error determining whether device is unlocked.\n");
380 		unlocked = ANDROID_VBOOT_UNLOCK;
381 		if (ops->write_is_device_unlocked(ops, &unlocked) != 0) {
382 			printf("Can not write lock state!\n");
383 			unlocked = ANDROID_VBOOT_LOCK;
384 		}
385 		if (ops->read_is_device_unlocked(ops, &unlocked) != 0) {
386 			printf("Can not read lock state!\n");
387 			unlocked = ANDROID_VBOOT_LOCK;
388 		}
389 	}
390 
391 	flags = AVB_SLOT_VERIFY_FLAGS_NONE;
392 	if (unlocked)
393 		flags |= AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR;
394 
395 	for (n = 0; n < SLOT_NUM; n++) {
396 		verify_result = avb_slot_verify(ops,
397 						requested_partitions,
398 						slot_suffixes[n],
399 						flags,
400 						AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE,
401 						&slot_data[n]);
402 		switch (verify_result) {
403 		case AVB_SLOT_VERIFY_RESULT_OK:
404 			break;
405 
406 		case AVB_SLOT_VERIFY_RESULT_ERROR_INVALID_METADATA:
407 		case AVB_SLOT_VERIFY_RESULT_ERROR_UNSUPPORTED_VERSION:
408 		/* Even with AVB_SLOT_VERIFY_FLAGS_ALLOW_VERIFICATION_ERROR
409 		 * these mean game over.
410 		 */
411 			printf("Invalid metadata!\n");
412 			goto out;
413 
414 		/* explicit fallthrough. */
415 		case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION:
416 			printf("Error verify!\n");
417 			goto out;
418 		case AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX:
419 			printf("error rollback index!\n");
420 			goto out;
421 		case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED:
422 			printf("error key!\n");
423 			goto out;
424 		default:
425 			printf("Some abnormal condition occur!\n");
426 			goto out;
427 		}
428 	}
429 	debug("partition_name = %s\n", slot_data[0]->vbmeta_images->partition_name);
430 	debug("vbmeta_size = %d\n", slot_data[0]->vbmeta_images->vbmeta_size);
431 
432 	for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_LOCATIONS; n++) {
433 		uint64_t rollback_index_value = 0;
434 		if (slot_data[0] != NULL && slot_data[1] != NULL) {
435 			uint64_t a_rollback_index = slot_data[0]->rollback_indexes[n];
436 			uint64_t b_rollback_index = slot_data[1]->rollback_indexes[n];
437 			rollback_index_value =
438 				(a_rollback_index < b_rollback_index ? a_rollback_index
439 								: b_rollback_index);
440 		} else if (slot_data[0] != NULL) {
441 			rollback_index_value = slot_data[0]->rollback_indexes[n];
442 		} else if (slot_data[1] != NULL) {
443 			rollback_index_value = slot_data[1]->rollback_indexes[n];
444 		}
445 
446 		io_ret = ops->read_rollback_index(
447 			ops, n, &stored_rollback_index);
448 		if (io_ret != AVB_IO_RESULT_OK)
449 			goto out;
450 		snprintf(temp, sizeof(uint64_t) + 1, "%lld",
451 			 stored_rollback_index);
452 		strncat(buffer, temp, ROLLBACK_MAX_SIZE);
453 		strncat(buffer, ":", 1);
454 		snprintf(temp, sizeof(uint64_t) + 1, "%lld",
455 			 rollback_index_value);
456 		strncat(buffer, temp, ROLLBACK_MAX_SIZE);
457 		strncat(buffer, ",", 1);
458 	}
459 
460 	for (n = 0; n < SLOT_NUM; n++) {
461 		avb_vbmeta_image_header_to_host_byte_order((AvbVBMetaImageHeader *)
462 							   slot_data[n]->vbmeta_images->\
463 							   vbmeta_data,
464 							   &vbmeta_header);
465 		if (vbmeta_header.public_key_metadata_size > 0) {
466 			metadata = (AvbAtxPublicKeyMetadata *)(slot_data[n]->\
467 				vbmeta_images->vbmeta_data +
468 			   	sizeof(AvbVBMetaImageHeader) +
469 			   	vbmeta_header.authentication_data_block_size +
470 			   	vbmeta_header.public_key_metadata_offset);
471 			if (n == 0) {
472 				pik_rollback_index =
473 					metadata->product_intermediate_key_certificate.\
474 					signed_data.key_version;
475 				psk_rollback_index =
476 					metadata->product_signing_key_certificate.\
477 					signed_data.key_version;
478 			}
479 
480 			if (pik_rollback_index > metadata->\
481 				product_intermediate_key_certificate.\
482 				signed_data.key_version) {
483 				pik_rollback_index = metadata->\
484 				product_intermediate_key_certificate.\
485 				signed_data.key_version;
486 			}
487 
488 			if (psk_rollback_index > metadata->\
489 				product_signing_key_certificate.\
490 				signed_data.key_version) {
491 				psk_rollback_index = metadata->\
492 				product_signing_key_certificate.\
493 				signed_data.key_version;
494 			}
495 		}
496 	}
497 	io_ret =
498 		ops->read_rollback_index(ops,
499 					 AVB_ATX_PIK_VERSION_LOCATION,
500 					 &stored_rollback_index);
501 	if (io_ret != AVB_IO_RESULT_OK) {
502 		avb_error("Failed to read PIK minimum version.\n");
503 		goto out;
504 	}
505 	/* PIK rollback index */
506 	snprintf(temp, sizeof(uint64_t) + 1, "%lld", stored_rollback_index);
507 	strncat(buffer, temp, ROLLBACK_MAX_SIZE);
508 	strncat(buffer, ":", 1);
509 	snprintf(temp, sizeof(uint64_t) + 1, "%lld", pik_rollback_index);
510 	strncat(buffer, temp, ROLLBACK_MAX_SIZE);
511 	strncat(buffer, ",", 1);
512 	io_ret = ops->read_rollback_index(ops,
513 					  AVB_ATX_PSK_VERSION_LOCATION,
514 					  &stored_rollback_index);
515 	if (io_ret != AVB_IO_RESULT_OK) {
516 		avb_error("Failed to read PSK minimum version.\n");
517 		goto out;
518 	}
519 	/* PSK rollback index */
520 	snprintf(temp, sizeof(uint64_t) + 1, "%lld", stored_rollback_index);
521 	strncat(buffer, temp, ROLLBACK_MAX_SIZE);
522 	strncat(buffer, ":", 1);
523 	snprintf(temp, sizeof(uint64_t) + 1, "%lld", psk_rollback_index);
524 	strncat(buffer, temp, ROLLBACK_MAX_SIZE);
525 	debug("%s\n", buffer);
526 
527 	for (n = 0; n < SLOT_NUM; n++) {
528 		if (slot_data[n] != NULL) {
529 			avb_slot_verify_data_free(slot_data[n]);
530 		}
531 	}
532 	avb_ops_user_free(ops);
533 
534 	return 0;
535 out:
536 	for (n = 0; n < SLOT_NUM; n++) {
537 		if (slot_data[n] != NULL) {
538 			avb_slot_verify_data_free(slot_data[n]);
539 		}
540 	}
541 	avb_ops_user_free(ops);
542 
543 	return -1;
544 }
545 
546 int rk_avb_read_bootloader_locked_flag(uint8_t *flag)
547 {
548 #ifdef CONFIG_OPTEE_CLIENT
549 	if (trusty_read_vbootkey_enable_flag(flag)) {
550 		return -1;
551 	}
552 	return 0;
553 #else
554 	return -1;
555 #endif
556 }
557 
558 void rk_avb_get_at_vboot_state(char *buf)
559 {
560 	char temp_buffer[150] = {0};
561 	char temp_flag = 0;
562 	char crlf[2] = {'\n', 0};
563 	char *lock_val = NULL;
564 	char *unlocK_dis_val = NULL;
565 	char *perm_attr_flag = NULL;
566 	char *bootloader_locked_flag = NULL;
567 	char *lock_state = "bootloader-locked=";
568 	char *btld_min_ver = "bootloader-min-versions=";
569 	char *avb_perm_attr_set = "avb-perm-attr-set=";
570 	char *avb_lock = "avb-locked=";
571 	char *avb_unlock_dis = "avb-unlock-disabled=";
572 	char *avb_min_ver = "avb-min-versions=";
573 
574 	if (rk_avb_read_perm_attr_flag((uint8_t *)&temp_flag)) {
575 		printf("Can not read perm_attr_flag!\n");
576 		perm_attr_flag = "";
577 	} else {
578 		perm_attr_flag = temp_flag ? "1" : "0";
579 	}
580 	sprintf(buf, "%s%s%s%s", buf, avb_perm_attr_set, perm_attr_flag, crlf);
581 
582 	if (rk_avb_read_lock_state((uint8_t *)&temp_flag)) {
583 		printf("Can not read lock state!\n");
584 		lock_val = "";
585 		unlocK_dis_val = "";
586 	} else {
587 		lock_val = (temp_flag & LOCK_MASK) ? "0" : "1";
588 		unlocK_dis_val = (temp_flag & UNLOCK_DISABLE_MASK) ? "1" : "0";
589 	}
590 	sprintf(buf, "%s%s%s%s%s%s%s", buf, avb_lock, lock_val, crlf,
591 		avb_unlock_dis, unlocK_dis_val, crlf);
592 
593 	if (rk_avb_read_bootloader_locked_flag((uint8_t *)&temp_flag)) {
594 		printf("Can not read bootloader locked flag!\n");
595 		bootloader_locked_flag = "";
596 	} else {
597 		bootloader_locked_flag = temp_flag ? "1" : "0";
598 	}
599 	sprintf(buf, "%s%s%s%s", buf, lock_state, bootloader_locked_flag, crlf);
600 
601 	if (rk_avb_read_all_rollback_index(temp_buffer))
602 		printf("Can not avb_min_ver!\n");
603 	sprintf(buf, "%s%s%s%s", buf, avb_min_ver, temp_buffer, crlf);
604 
605 	/* miniloader is not ready, bootloader-min-versions=-1 */
606 	sprintf(buf, "%s%s%d%s", buf, btld_min_ver, -1, crlf);
607 }
608 
609 int rk_avb_get_ab_info(AvbABData* ab_data)
610 {
611 	AvbOps* ops;
612 	AvbIOResult io_ret = AVB_IO_RESULT_OK;
613 	int ret = 0;
614 
615 	ops = avb_ops_user_new();
616 	if (ops == NULL) {
617 		printf("%s: avb_ops_user_new() failed!\n", __FILE__);
618 		return -1;
619 	}
620 
621 	io_ret = ops->ab_ops->read_ab_metadata(ops->ab_ops, ab_data);
622 	if (io_ret != AVB_IO_RESULT_OK) {
623 		avb_error("I/O error while loading A/B metadata.\n");
624 		ret = -1;
625 	}
626 
627 	avb_ops_user_free(ops);
628 
629 	return ret;
630 }
631 
632 int rk_avb_get_part_has_slot_info(const char *base_name)
633 {
634 	char *part_name;
635 	int part_num;
636 	size_t part_name_len;
637 	disk_partition_t part_info;
638 	struct blk_desc *dev_desc;
639 	const char *slot_suffix = "_a";
640 
641 	dev_desc = rockchip_get_bootdev();
642 	if (!dev_desc) {
643 		printf("%s: Could not find device!\n", __func__);
644 		return -1;
645 	}
646 
647 	if (base_name == NULL) {
648 		printf("The base_name is NULL!\n");
649 		return -1;
650 	}
651 
652 	part_name_len = strlen(base_name) + 1;
653 	part_name_len += strlen(slot_suffix);
654 	part_name = malloc(part_name_len);
655 	if (!part_name) {
656 		printf("%s can not malloc a buffer!\n", __FILE__);
657 		return -1;
658 	}
659 
660 	memset(part_name, 0, part_name_len);
661 	snprintf(part_name, part_name_len, "%s%s", base_name, slot_suffix);
662 	part_num = part_get_info_by_name(dev_desc, part_name, &part_info);
663 	if (part_num < 0) {
664 		printf("Could not find partition \"%s\"\n", part_name);
665 		part_num = -1;
666 	}
667 
668 	free(part_name);
669 	return part_num;
670 }
671