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
memparse(const char * ptr,char ** retptr)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
env_init_parts(struct blk_desc * dev_desc,struct list_head * parts_head)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
part_print_env(struct blk_desc * dev_desc)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
part_get_info_env(struct blk_desc * dev_desc,int idx,disk_partition_t * info)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
part_test_env(struct blk_desc * dev_desc)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