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