xref: /rk3399_rockchip-uboot/disk/part_env.c (revision 8c7c24c01a6f59f93e6564743e0e75c973d73387)
1 /*
2  * (C) Copyright 2022 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <envf.h>
9 #include <malloc.h>
10 
11 #ifdef HAVE_BLOCK_DEVICE
12 struct env_part {
13 	char name[PART_NAME_LEN];
14 	lbaint_t start;
15 	lbaint_t size;
16 	struct list_head node;
17 };
18 
19 #define DEV_NUM(dev_desc)  (((dev_desc)->if_type << 8) + (dev_desc)->devnum)
20 
21 /*
22  * What's this?
23  *
24  * There maybe different storage media will use this partition driver,
25  * e.g. rkand with SD card. So we need a flag info to recognize it
26  * and rebuild partition table.
27  */
28 static int dev_num = -1;
29 static LIST_HEAD(parts_head);
30 
31 static unsigned long long memparse(const char *ptr, char **retptr)
32 {
33 	char *endptr;	/* local pointer to end of parsed string */
34 	unsigned long long ret = simple_strtoull(ptr, &endptr, 0);
35 
36 	switch (*endptr) {
37 	case 'E':
38 	case 'e':
39 		ret <<= 10;
40 		/* fall through */
41 	case 'P':
42 	case 'p':
43 		ret <<= 10;
44 		/* fall through */
45 	case 'T':
46 	case 't':
47 		ret <<= 10;
48 		/* fall through */
49 	case 'G':
50 	case 'g':
51 		ret <<= 10;
52 		/* fall through */
53 	case 'M':
54 	case 'm':
55 		ret <<= 10;
56 		/* fall through */
57 	case 'K':
58 	case 'k':
59 		ret <<= 10;
60 		endptr++;
61 	default:
62 		break;
63 	}
64 
65 	if (retptr)
66 		*retptr = endptr;
67 
68 	return ret;
69 }
70 
71 static int env_init_parts(struct blk_desc *dev_desc, struct list_head *parts_head)
72 {
73 	struct env_part *part;
74 	lbaint_t size, start = 0;
75 	int len, offset = 0;
76 	char *next, *pend;
77 	char *parts_list = NULL;
78 
79 #if CONFIG_IS_ENABLED(ENVF)
80 	parts_list = envf_get(dev_desc, "mtdparts");
81 	if (!parts_list)
82 		parts_list = envf_get(dev_desc, "blkdevparts");
83 #else
84 	parts_list = ENV_PARTITIONS;
85 #endif
86 	if (!parts_list) {
87 		printf("No env partition table\n");
88 		return -EINVAL;
89 	}
90 
91 	next = strchr(parts_list, ':');
92 	INIT_LIST_HEAD(parts_head);
93 	while (next) {
94 		/* Skip ':' and ',' */
95 		next++;
96 		if (*next == '-') {
97 			size = (~0UL);
98 			next++;
99 		} else {
100 			size = (lbaint_t)memparse(next, &next);
101 		}
102 		if (*next == '@') {
103 			next++;
104 			start = (lbaint_t)memparse(next, &next);
105 		}
106 		next++;
107 		pend = strchr(next, ')');
108 		if (!pend)
109 			break;
110 
111 		len = min_t(int, pend - next, PART_NAME_LEN);
112 		part = malloc(sizeof(*part));
113 		if (!part)
114 			break;
115 		part->start = (start + offset) / dev_desc->blksz;
116 		start += size;
117 		/* Last partition use all remain space */
118 		if (size == (~0UL))
119 			part->size = dev_desc->lba - part->start;
120 		else
121 			part->size = size / dev_desc->blksz;
122 		strncpy(part->name, next, len);
123 		part->name[len] = '\0';
124 		list_add_tail(&part->node, parts_head);
125 		next = strchr(next, ',');
126 	}
127 
128 	dev_num = DEV_NUM(dev_desc);
129 
130 	return 0;
131 }
132 
133 void part_print_env(struct blk_desc *dev_desc)
134 {
135 	struct list_head *node;
136 	struct env_part *p;
137 	int i = 0;
138 	int ret;
139 
140 	if (list_empty(&parts_head) || (dev_num != DEV_NUM(dev_desc))) {
141 		ret = env_init_parts(dev_desc, &parts_head);
142 		if (ret) {
143 			printf("%s: Invalid env parameter\n", __func__);
144 			return;
145 		}
146 	}
147 
148 	printf("Part\tStart LBA\tSize\t\tName\n");
149 	list_for_each(node, &parts_head) {
150 		p = list_entry(node, struct env_part, node);
151 		printf("%3d\t0x%08lx\t0x%08lx\t%s\n", (i++ + 1),
152 		       p->start, p->size, p->name);
153 	}
154 }
155 
156 static int part_get_info_env(struct blk_desc *dev_desc, int idx,
157 			     disk_partition_t *info)
158 {
159 	struct env_part *p = NULL;
160 	struct list_head *node;
161 	int part_num = 0;
162 	int ret = 0;
163 
164 	if (idx < 1) {
165 		printf("%s: Invalid partition no.%d\n", __func__, idx);
166 		return -EINVAL;
167 	}
168 
169 	if (list_empty(&parts_head) || (dev_num != DEV_NUM(dev_desc))) {
170 		ret = env_init_parts(dev_desc, &parts_head);
171 		if (ret) {
172 			printf("%s: Invalid env partition\n", __func__);
173 			return -1;
174 		}
175 	}
176 
177 	list_for_each(node, &parts_head) {
178 		p = list_entry(node, struct env_part, node);
179 		part_num++;
180 		if (idx == part_num)
181 			break;
182 	}
183 
184 	if (part_num < idx) {
185 		debug("%s: Invalid partition no.%d\n", __func__, idx);
186 		return -EINVAL;
187 	}
188 
189 	info->start = p->start;
190 	info->size  = p->size;
191 	info->blksz = dev_desc->blksz;
192 	info->bootable = 0;
193 
194 	sprintf((char *)info->name, "%s", p->name);
195 	strcpy((char *)info->type, "U-Boot");
196 
197 	return 0;
198 }
199 
200 static int part_test_env(struct blk_desc *dev_desc)
201 {
202 	return env_init_parts(dev_desc, &parts_head) ? -1 : 0;
203 }
204 
205 /*
206  * Add an 'a_b_' prefix so it comes before 'a_efi'.
207  */
208 U_BOOT_PART_TYPE(a_b_env) = {
209 	.name		= "ENV",
210 	.part_type	= PART_TYPE_ENV,
211 	.max_entries	= ENV_ENTRY_NUMBERS,
212 	.get_info	= part_get_info_ptr(part_get_info_env),
213 	.print		= part_print_ptr(part_print_env),
214 	.test		= part_test_env,
215 };
216 #endif
217 
218