• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (C) 2016 The Android Open Source Project
4  */
5 
6 #include <common.h>
7 #include <env.h>
8 #include <fastboot.h>
9 #include <fastboot-internal.h>
10 #include <fb_mmc.h>
11 #include <fb_nand.h>
12 #include <fs.h>
13 #include <version.h>
14 
15 static void getvar_version(char *var_parameter, char *response);
16 static void getvar_version_bootloader(char *var_parameter, char *response);
17 static void getvar_downloadsize(char *var_parameter, char *response);
18 static void getvar_serialno(char *var_parameter, char *response);
19 static void getvar_version_baseband(char *var_parameter, char *response);
20 static void getvar_product(char *var_parameter, char *response);
21 static void getvar_platform(char *var_parameter, char *response);
22 static void getvar_current_slot(char *var_parameter, char *response);
23 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
24 static void getvar_has_slot(char *var_parameter, char *response);
25 #endif
26 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
27 static void getvar_partition_type(char *part_name, char *response);
28 #endif
29 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
30 static void getvar_partition_size(char *part_name, char *response);
31 #endif
32 static void getvar_is_userspace(char *var_parameter, char *response);
33 
34 static const struct {
35 	const char *variable;
36 	void (*dispatch)(char *var_parameter, char *response);
37 } getvar_dispatch[] = {
38 	{
39 		.variable = "version",
40 		.dispatch = getvar_version
41 	}, {
42 		.variable = "version-bootloader",
43 		.dispatch = getvar_version_bootloader
44 	}, {
45 		.variable = "downloadsize",
46 		.dispatch = getvar_downloadsize
47 	}, {
48 		.variable = "max-download-size",
49 		.dispatch = getvar_downloadsize
50 	}, {
51 		.variable = "serialno",
52 		.dispatch = getvar_serialno
53 	}, {
54 		.variable = "version-baseband",
55 		.dispatch = getvar_version_baseband
56 	}, {
57 		.variable = "product",
58 		.dispatch = getvar_product
59 	}, {
60 		.variable = "platform",
61 		.dispatch = getvar_platform
62 	}, {
63 		.variable = "current-slot",
64 		.dispatch = getvar_current_slot
65 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
66 	}, {
67 		.variable = "has-slot",
68 		.dispatch = getvar_has_slot
69 #endif
70 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
71 	}, {
72 		.variable = "partition-type",
73 		.dispatch = getvar_partition_type
74 #endif
75 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
76 	}, {
77 		.variable = "partition-size",
78 		.dispatch = getvar_partition_size
79 #endif
80 	}, {
81 		.variable = "is-userspace",
82 		.dispatch = getvar_is_userspace
83 	}
84 };
85 
86 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
87 /**
88  * Get partition number and size for any storage type.
89  *
90  * Can be used to check if partition with specified name exists.
91  *
92  * If error occurs, this function guarantees to fill @p response with fail
93  * string. @p response can be rewritten in caller, if needed.
94  *
95  * @param[in] part_name Info for which partition name to look for
96  * @param[in,out] response Pointer to fastboot response buffer
97  * @param[out] size If not NULL, will contain partition size (in blocks)
98  * @return Partition number or negative value on error
99  */
getvar_get_part_info(const char * part_name,char * response,size_t * size)100 static int getvar_get_part_info(const char *part_name, char *response,
101 				size_t *size)
102 {
103 	int r;
104 # if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
105 	struct blk_desc *dev_desc;
106 	disk_partition_t part_info;
107 
108 	r = fastboot_mmc_get_part_info(part_name, &dev_desc, &part_info,
109 				       response);
110 	if (r >= 0 && size)
111 		*size = part_info.size;
112 # elif CONFIG_IS_ENABLED(FASTBOOT_FLASH_NAND)
113 	struct part_info *part_info;
114 
115 	r = fastboot_nand_get_part_info(part_name, &part_info, response);
116 	if (r >= 0 && size)
117 		*size = part_info->size;
118 # else
119 	fastboot_fail("this storage is not supported in bootloader", response);
120 	r = -ENODEV;
121 # endif
122 
123 	return r;
124 }
125 #endif
126 
getvar_version(char * var_parameter,char * response)127 static void getvar_version(char *var_parameter, char *response)
128 {
129 	fastboot_okay(FASTBOOT_VERSION, response);
130 }
131 
getvar_version_bootloader(char * var_parameter,char * response)132 static void getvar_version_bootloader(char *var_parameter, char *response)
133 {
134 	fastboot_okay(U_BOOT_VERSION, response);
135 }
136 
getvar_downloadsize(char * var_parameter,char * response)137 static void getvar_downloadsize(char *var_parameter, char *response)
138 {
139 	fastboot_response("OKAY", response, "0x%08x", fastboot_buf_size);
140 }
141 
getvar_serialno(char * var_parameter,char * response)142 static void getvar_serialno(char *var_parameter, char *response)
143 {
144 	const char *tmp = env_get("serial#");
145 
146 	if (tmp)
147 		fastboot_okay(tmp, response);
148 	else
149 		fastboot_fail("Value not set", response);
150 }
151 
getvar_version_baseband(char * var_parameter,char * response)152 static void getvar_version_baseband(char *var_parameter, char *response)
153 {
154 	fastboot_okay("N/A", response);
155 }
156 
getvar_product(char * var_parameter,char * response)157 static void getvar_product(char *var_parameter, char *response)
158 {
159 	const char *board = env_get("board");
160 
161 	if (board)
162 		fastboot_okay(board, response);
163 	else
164 		fastboot_fail("Board not set", response);
165 }
166 
getvar_platform(char * var_parameter,char * response)167 static void getvar_platform(char *var_parameter, char *response)
168 {
169 	const char *p = env_get("platform");
170 
171 	if (p)
172 		fastboot_okay(p, response);
173 	else
174 		fastboot_fail("platform not set", response);
175 }
176 
getvar_current_slot(char * var_parameter,char * response)177 static void getvar_current_slot(char *var_parameter, char *response)
178 {
179 	/* A/B not implemented, for now always return "a" */
180 	fastboot_okay("a", response);
181 }
182 
183 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
getvar_has_slot(char * part_name,char * response)184 static void getvar_has_slot(char *part_name, char *response)
185 {
186 	char part_name_wslot[PART_NAME_LEN];
187 	size_t len;
188 	int r;
189 
190 	if (!part_name || part_name[0] == '\0')
191 		goto fail;
192 
193 	/* part_name_wslot = part_name + "_a" */
194 	len = strlcpy(part_name_wslot, part_name, PART_NAME_LEN - 3);
195 	if (len > PART_NAME_LEN - 3)
196 		goto fail;
197 	strcat(part_name_wslot, "_a");
198 
199 	r = getvar_get_part_info(part_name_wslot, response, NULL);
200 	if (r >= 0) {
201 		fastboot_okay("yes", response); /* part exists and slotted */
202 		return;
203 	}
204 
205 	r = getvar_get_part_info(part_name, response, NULL);
206 	if (r >= 0)
207 		fastboot_okay("no", response); /* part exists but not slotted */
208 
209 	/* At this point response is filled with okay or fail string */
210 	return;
211 
212 fail:
213 	fastboot_fail("invalid partition name", response);
214 }
215 #endif
216 
217 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH_MMC)
getvar_partition_type(char * part_name,char * response)218 static void getvar_partition_type(char *part_name, char *response)
219 {
220 	int r;
221 	struct blk_desc *dev_desc;
222 	disk_partition_t part_info;
223 
224 	r = fastboot_mmc_get_part_info(part_name, &dev_desc, &part_info,
225 				       response);
226 	if (r >= 0) {
227 		r = fs_set_blk_dev_with_part(dev_desc, r);
228 		if (r < 0)
229 			fastboot_fail("failed to set partition", response);
230 		else
231 			fastboot_okay(fs_get_type_name(), response);
232 	}
233 }
234 #endif
235 
236 #if CONFIG_IS_ENABLED(FASTBOOT_FLASH)
getvar_partition_size(char * part_name,char * response)237 static void getvar_partition_size(char *part_name, char *response)
238 {
239 	int r;
240 	size_t size;
241 
242 	r = getvar_get_part_info(part_name, response, &size);
243 	if (r >= 0)
244 		fastboot_response("OKAY", response, "0x%016zx", size);
245 }
246 #endif
247 
getvar_is_userspace(char * var_parameter,char * response)248 static void getvar_is_userspace(char *var_parameter, char *response)
249 {
250 	fastboot_okay("no", response);
251 }
252 
253 /**
254  * fastboot_getvar() - Writes variable indicated by cmd_parameter to response.
255  *
256  * @cmd_parameter: Pointer to command parameter
257  * @response: Pointer to fastboot response buffer
258  *
259  * Look up cmd_parameter first as an environment variable of the form
260  * fastboot.<cmd_parameter>, if that exists return use its value to set
261  * response.
262  *
263  * Otherwise lookup the name of variable and execute the appropriate
264  * function to return the requested value.
265  */
fastboot_getvar(char * cmd_parameter,char * response)266 void fastboot_getvar(char *cmd_parameter, char *response)
267 {
268 	if (!cmd_parameter) {
269 		fastboot_fail("missing var", response);
270 	} else {
271 #define FASTBOOT_ENV_PREFIX	"fastboot."
272 		int i;
273 		char *var_parameter = cmd_parameter;
274 		char envstr[FASTBOOT_RESPONSE_LEN];
275 		const char *s;
276 
277 		snprintf(envstr, sizeof(envstr) - 1,
278 			 FASTBOOT_ENV_PREFIX "%s", cmd_parameter);
279 		s = env_get(envstr);
280 		if (s) {
281 			fastboot_response("OKAY", response, "%s", s);
282 			return;
283 		}
284 
285 		strsep(&var_parameter, ":");
286 		for (i = 0; i < ARRAY_SIZE(getvar_dispatch); ++i) {
287 			if (!strcmp(getvar_dispatch[i].variable,
288 				    cmd_parameter)) {
289 				getvar_dispatch[i].dispatch(var_parameter,
290 							    response);
291 				return;
292 			}
293 		}
294 		pr_warn("WARNING: unknown variable: %s\n", cmd_parameter);
295 		fastboot_fail("Variable not implemented", response);
296 	}
297 }
298