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 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 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 const char *parts_prefix[] = { "mtdparts", "blkdevparts", }; 86 int i; 87 88 for (i = 0; i < ARRAY_SIZE(parts_prefix); i++) { 89 parts_list = env_get(parts_prefix[i]); 90 if (parts_list) 91 break; 92 } 93 #endif 94 if (!parts_list) 95 return -EINVAL; 96 97 next = strchr(parts_list, ':'); 98 INIT_LIST_HEAD(parts_head); 99 while (next) { 100 /* Skip ':' and ',' */ 101 next++; 102 if (*next == '-') { 103 size = (~0UL); 104 next++; 105 } else { 106 size = (lbaint_t)memparse(next, &next); 107 } 108 if (*next == '@') { 109 next++; 110 start = (lbaint_t)memparse(next, &next); 111 } 112 next++; 113 pend = strchr(next, ')'); 114 if (!pend) 115 break; 116 117 len = min_t(int, pend - next, PART_NAME_LEN); 118 part = malloc(sizeof(*part)); 119 if (!part) 120 break; 121 part->start = (start + offset) / dev_desc->blksz; 122 start += size; 123 /* Last partition use all remain space */ 124 if (size == (~0UL)) 125 part->size = dev_desc->lba - part->start; 126 else 127 part->size = size / dev_desc->blksz; 128 strncpy(part->name, next, len); 129 part->name[len] = '\0'; 130 list_add_tail(&part->node, parts_head); 131 next = strchr(next, ','); 132 } 133 134 dev_num = DEV_NUM(dev_desc); 135 136 return 0; 137 } 138 139 void part_print_env(struct blk_desc *dev_desc) 140 { 141 struct list_head *node; 142 struct env_part *p; 143 int i = 0; 144 int ret; 145 146 if (list_empty(&parts_head) || (dev_num != DEV_NUM(dev_desc))) { 147 ret = env_init_parts(dev_desc, &parts_head); 148 if (ret) { 149 printf("%s: Invalid env parameter\n", __func__); 150 return; 151 } 152 } 153 154 printf("Part\tStart LBA\tSize\t\tName\n"); 155 list_for_each(node, &parts_head) { 156 p = list_entry(node, struct env_part, node); 157 printf("%3d\t0x%08lx\t0x%08lx\t%s\n", (i++ + 1), 158 p->start, p->size, p->name); 159 } 160 } 161 162 static int part_get_info_env(struct blk_desc *dev_desc, int idx, 163 disk_partition_t *info) 164 { 165 struct env_part *p = NULL; 166 struct list_head *node; 167 int part_num = 1; 168 int ret = 0; 169 170 if (idx < 1) { 171 printf("%s: Invalid partition no.%d\n", __func__, idx); 172 return -EINVAL; 173 } 174 175 if (list_empty(&parts_head) || (dev_num != DEV_NUM(dev_desc))) { 176 ret = env_init_parts(dev_desc, &parts_head); 177 if (ret) { 178 printf("%s: Invalid env partition\n", __func__); 179 return -1; 180 } 181 } 182 183 list_for_each(node, &parts_head) { 184 p = list_entry(node, struct env_part, node); 185 if (idx == part_num) 186 break; 187 part_num++; 188 } 189 190 if (part_num < idx) { 191 debug("%s: Invalid partition no.%d\n", __func__, idx); 192 return -EINVAL; 193 } 194 195 info->start = p->start; 196 info->size = p->size; 197 info->blksz = dev_desc->blksz; 198 info->bootable = 0; 199 200 sprintf((char *)info->name, "%s", p->name); 201 strcpy((char *)info->type, "U-Boot"); 202 203 return 0; 204 } 205 206 static int part_test_env(struct blk_desc *dev_desc) 207 { 208 return env_init_parts(dev_desc, &parts_head) ? -1 : 0; 209 } 210 211 /* 212 * Add an 'a_b_' prefix so it comes before 'a_efi'. 213 */ 214 U_BOOT_PART_TYPE(a_b_env) = { 215 .name = "ENV", 216 .part_type = PART_TYPE_ENV, 217 .max_entries = ENV_ENTRY_NUMBERS, 218 .get_info = part_get_info_ptr(part_get_info_env), 219 .print = part_print_ptr(part_print_env), 220 .test = part_test_env, 221 }; 222 #endif 223 224