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 #ifdef CONFIG_SPL_BUILD 31 static char *env_parts_list; 32 33 void env_part_list_init(const char *list) 34 { 35 env_parts_list = (char *)list; 36 } 37 #endif 38 39 static unsigned long long memparse(const char *ptr, char **retptr) 40 { 41 char *endptr; /* local pointer to end of parsed string */ 42 unsigned long long ret = simple_strtoull(ptr, &endptr, 0); 43 44 switch (*endptr) { 45 case 'E': 46 case 'e': 47 ret <<= 10; 48 /* fall through */ 49 case 'P': 50 case 'p': 51 ret <<= 10; 52 /* fall through */ 53 case 'T': 54 case 't': 55 ret <<= 10; 56 /* fall through */ 57 case 'G': 58 case 'g': 59 ret <<= 10; 60 /* fall through */ 61 case 'M': 62 case 'm': 63 ret <<= 10; 64 /* fall through */ 65 case 'K': 66 case 'k': 67 ret <<= 10; 68 endptr++; 69 default: 70 break; 71 } 72 73 if (retptr) 74 *retptr = endptr; 75 76 return ret; 77 } 78 79 static int env_init_parts(struct blk_desc *dev_desc, struct list_head *parts_head) 80 { 81 struct env_part *part; 82 lbaint_t size, start = 0; 83 int len, offset = 0; 84 char *next, *pend; 85 char *parts_list = NULL; 86 #ifndef CONFIG_SPL_BUILD 87 const char *parts_prefix[] = { "mtdparts", "blkdevparts", }; 88 int i; 89 90 for (i = 0; i < ARRAY_SIZE(parts_prefix); i++) { 91 parts_list = env_get(parts_prefix[i]); 92 if (parts_list) 93 break; 94 } 95 #else 96 parts_list = env_parts_list; 97 #endif 98 if (!parts_list) 99 return -EINVAL; 100 101 next = strchr(parts_list, ':'); 102 INIT_LIST_HEAD(parts_head); 103 while (next) { 104 /* Skip ':' and ',' */ 105 next++; 106 if (*next == '-') { 107 size = (~0UL); 108 next++; 109 } else { 110 size = (lbaint_t)memparse(next, &next); 111 } 112 if (*next == '@') { 113 next++; 114 start = (lbaint_t)memparse(next, &next); 115 } 116 next++; 117 pend = strchr(next, ')'); 118 if (!pend) 119 break; 120 121 len = min_t(int, pend - next, PART_NAME_LEN); 122 part = malloc(sizeof(*part)); 123 if (!part) 124 break; 125 part->start = (start + offset) / dev_desc->blksz; 126 start += size; 127 /* Last partition use all remain space */ 128 if (size == (~0UL)) 129 part->size = dev_desc->lba - part->start; 130 else 131 part->size = size / dev_desc->blksz; 132 strncpy(part->name, next, len); 133 part->name[len] = '\0'; 134 list_add_tail(&part->node, parts_head); 135 next = strchr(next, ','); 136 } 137 138 dev_num = DEV_NUM(dev_desc); 139 140 /* Add into "bootargs" */ 141 #ifndef CONFIG_SPL_BUILD 142 char *parts_cmdline; 143 144 parts_cmdline = 145 calloc(1, strlen(parts_list) + strlen(parts_prefix[i]) + 2); 146 if (!parts_cmdline) 147 return -ENOMEM; 148 strcat(parts_cmdline, parts_prefix[i]); 149 strcat(parts_cmdline, "="); 150 strcat(parts_cmdline, parts_list); 151 env_update("bootargs", parts_cmdline); 152 free(parts_cmdline); 153 #endif 154 155 printf("PartType: ENV\n"); 156 157 return 0; 158 } 159 160 void part_print_env(struct blk_desc *dev_desc) 161 { 162 struct list_head *node; 163 struct env_part *p; 164 int i = 0; 165 int ret; 166 167 if (list_empty(&parts_head) || (dev_num != DEV_NUM(dev_desc))) { 168 ret = env_init_parts(dev_desc, &parts_head); 169 if (ret) { 170 printf("%s: Invalid env parameter\n", __func__); 171 return; 172 } 173 } 174 175 printf("Part\tStart LBA\tSize\t\tName\n"); 176 list_for_each(node, &parts_head) { 177 p = list_entry(node, struct env_part, node); 178 printf("%3d\t0x%08lx\t0x%08lx\t%s\n", (i++ + 1), 179 p->start, p->size, p->name); 180 } 181 } 182 183 static int part_get_info_env(struct blk_desc *dev_desc, int idx, 184 disk_partition_t *info) 185 { 186 struct env_part *p = NULL; 187 struct list_head *node; 188 int part_num = 1; 189 int ret = 0; 190 191 if (idx < 1) { 192 printf("%s: Invalid partition no.%d\n", __func__, idx); 193 return -EINVAL; 194 } 195 196 if (list_empty(&parts_head) || (dev_num != DEV_NUM(dev_desc))) { 197 ret = env_init_parts(dev_desc, &parts_head); 198 if (ret) { 199 printf("%s: Invalid env partition\n", __func__); 200 return -1; 201 } 202 } 203 204 list_for_each(node, &parts_head) { 205 p = list_entry(node, struct env_part, node); 206 if (idx == part_num) 207 break; 208 part_num++; 209 } 210 211 if (part_num < idx) { 212 debug("%s: Invalid partition no.%d\n", __func__, idx); 213 return -EINVAL; 214 } 215 216 info->start = p->start; 217 info->size = p->size; 218 info->blksz = dev_desc->blksz; 219 info->bootable = 0; 220 221 sprintf((char *)info->name, "%s", p->name); 222 strcpy((char *)info->type, "U-Boot"); 223 224 return 0; 225 } 226 227 static int part_test_env(struct blk_desc *dev_desc) 228 { 229 return env_init_parts(dev_desc, &parts_head) ? -1 : 0; 230 } 231 232 /* 233 * Add an 'a_b_' prefix so it comes before 'a_efi'. 234 */ 235 U_BOOT_PART_TYPE(a_b_env) = { 236 .name = "ENV", 237 .part_type = PART_TYPE_ENV, 238 .max_entries = ENV_ENTRY_NUMBERS, 239 .get_info = part_get_info_ptr(part_get_info_env), 240 .print = part_print_ptr(part_print_env), 241 .test = part_test_env, 242 }; 243 #endif 244 245