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