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