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 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 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 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 = 0; 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 part_num++; 179 if (idx == part_num) 180 break; 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 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