xref: /linux/tools/power/acpi/tools/pfrut/pfrut.c (revision 621cde16e49b3ecf7d59a8106a20aaebfb4a59a9)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Platform Firmware Runtime Update tool to do Management
4  * Mode code injection/driver update and telemetry retrieval.
5  *
6  * This tool uses the interfaces provided by pfr_update and
7  * pfr_telemetry drivers. These interfaces are exposed via
8  * /dev/pfr_update and /dev/pfr_telemetry. Write operation
9  * on the /dev/pfr_update is to load the EFI capsule into
10  * kernel space. Mmap/read operations on /dev/pfr_telemetry
11  * could be used to read the telemetry data to user space.
12  */
13 #define _GNU_SOURCE
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <getopt.h>
22 #include <sys/ioctl.h>
23 #include <sys/mman.h>
24 #include <uuid/uuid.h>
25 #include PFRUT_HEADER
26 
27 char *capsule_name;
28 int action, query_cap, log_type, log_level, log_read, log_getinfo,
29 	revid, log_revid;
30 int set_log_level, set_log_type,
31 	set_revid, set_log_revid;
32 
33 char *progname;
34 
35 #define LOG_ERR		0
36 #define LOG_WARN	1
37 #define LOG_INFO	2
38 #define LOG_VERB	4
39 #define LOG_EXEC_IDX	0
40 #define LOG_HISTORY_IDX	1
41 #define REVID_1		1
42 #define REVID_2		2
43 
valid_log_level(int level)44 static int valid_log_level(int level)
45 {
46 	return level == LOG_ERR || level == LOG_WARN ||
47 	       level == LOG_INFO || level == LOG_VERB;
48 }
49 
valid_log_type(int type)50 static int valid_log_type(int type)
51 {
52 	return type == LOG_EXEC_IDX || type == LOG_HISTORY_IDX;
53 }
54 
valid_log_revid(int id)55 static inline int valid_log_revid(int id)
56 {
57 	return id == REVID_1 || id == REVID_2;
58 }
59 
help(void)60 static void help(void)
61 {
62 	fprintf(stderr,
63 		"usage: %s [OPTIONS]\n"
64 		" code injection:\n"
65 		"  -l, --load\n"
66 		"  -s, --stage\n"
67 		"  -a, --activate\n"
68 		"  -u, --update [stage and activate]\n"
69 		"  -q, --query\n"
70 		"  -d, --revid update\n"
71 		" telemetry:\n"
72 		"  -G, --getloginfo\n"
73 		"  -T, --type(0:execution, 1:history)\n"
74 		"  -L, --level(0, 1, 2, 4)\n"
75 		"  -R, --read\n"
76 		"  -D, --revid log\n",
77 		progname);
78 }
79 
80 char *option_string = "l:sauqd:GT:L:RD:h";
81 static struct option long_options[] = {
82 	{"load", required_argument, 0, 'l'},
83 	{"stage", no_argument, 0, 's'},
84 	{"activate", no_argument, 0, 'a'},
85 	{"update", no_argument, 0, 'u'},
86 	{"query", no_argument, 0, 'q'},
87 	{"getloginfo", no_argument, 0, 'G'},
88 	{"type", required_argument, 0, 'T'},
89 	{"level", required_argument, 0, 'L'},
90 	{"read", no_argument, 0, 'R'},
91 	{"setrev", required_argument, 0, 'd'},
92 	{"setrevlog", required_argument, 0, 'D'},
93 	{"help", no_argument, 0, 'h'},
94 	{}
95 };
96 
parse_options(int argc,char ** argv)97 static void parse_options(int argc, char **argv)
98 {
99 	int option_index = 0;
100 	char *pathname, *endptr;
101 	int opt;
102 
103 	pathname = strdup(argv[0]);
104 	progname = basename(pathname);
105 
106 	while ((opt = getopt_long_only(argc, argv, option_string,
107 				       long_options, &option_index)) != -1) {
108 		switch (opt) {
109 		case 'l':
110 			capsule_name = optarg;
111 			break;
112 		case 's':
113 			action = 1;
114 			break;
115 		case 'a':
116 			action = 2;
117 			break;
118 		case 'u':
119 			action = 3;
120 			break;
121 		case 'q':
122 			query_cap = 1;
123 			break;
124 		case 'G':
125 			log_getinfo = 1;
126 			break;
127 		case 'T':
128 			log_type = strtol(optarg, &endptr, 0);
129 			if (*endptr || (log_type != 0 && log_type != 1)) {
130 				printf("Number expected: type(0:execution, 1:history) - Quit.\n");
131 				exit(1);
132 			}
133 
134 			set_log_type = 1;
135 			break;
136 		case 'L':
137 			log_level = strtol(optarg, &endptr, 0);
138 			if (*endptr ||
139 			    (log_level != 0 && log_level != 1 &&
140 			     log_level != 2 && log_level != 4)) {
141 				printf("Number expected: level(0, 1, 2, 4) - Quit.\n");
142 				exit(1);
143 			}
144 
145 			set_log_level = 1;
146 			break;
147 		case 'R':
148 			log_read = 1;
149 			break;
150 		case 'd':
151 			revid = atoi(optarg);
152 			set_revid = 1;
153 			break;
154 		case 'D':
155 			log_revid = atoi(optarg);
156 			set_log_revid = 1;
157 			break;
158 		case 'h':
159 			help();
160 			exit(0);
161 		default:
162 			break;
163 		}
164 	}
165 }
166 
print_cap(struct pfru_update_cap_info * cap)167 void print_cap(struct pfru_update_cap_info *cap)
168 {
169 	char *uuid;
170 
171 	uuid = malloc(37);
172 	if (!uuid) {
173 		perror("Can not allocate uuid buffer\n");
174 		exit(1);
175 	}
176 
177 	printf("update capability:%d\n", cap->update_cap);
178 
179 	uuid_unparse(cap->code_type, uuid);
180 	printf("code injection image type:%s\n", uuid);
181 	printf("fw_version:%d\n", cap->fw_version);
182 	printf("code_rt_version:%d\n", cap->code_rt_version);
183 
184 	uuid_unparse(cap->drv_type, uuid);
185 	printf("driver update image type:%s\n", uuid);
186 	printf("drv_rt_version:%d\n", cap->drv_rt_version);
187 	printf("drv_svn:%d\n", cap->drv_svn);
188 
189 	uuid_unparse(cap->platform_id, uuid);
190 	printf("platform id:%s\n", uuid);
191 	uuid_unparse(cap->oem_id, uuid);
192 	printf("oem id:%s\n", uuid);
193 	printf("oem information length:%d\n", cap->oem_info_len);
194 
195 	free(uuid);
196 }
197 
main(int argc,char * argv[])198 int main(int argc, char *argv[])
199 {
200 	int fd_update, fd_update_log, fd_capsule;
201 	struct pfrt_log_data_info data_info;
202 	struct pfrt_log_info info;
203 	struct pfru_update_cap_info cap;
204 	void *addr_map_capsule;
205 	struct stat st;
206 	char *log_buf;
207 	int ret;
208 
209 	if (getuid() != 0) {
210 		printf("Please run the tool as root - Exiting.\n");
211 		return 1;
212 	}
213 
214 	parse_options(argc, argv);
215 
216 	fd_update = open("/dev/acpi_pfr_update0", O_RDWR);
217 	if (fd_update < 0) {
218 		printf("PFRU device not supported - Quit...\n");
219 		return 1;
220 	}
221 
222 	fd_update_log = open("/dev/acpi_pfr_telemetry0", O_RDWR);
223 	if (fd_update_log < 0) {
224 		printf("PFRT device not supported - Quit...\n");
225 		return 1;
226 	}
227 
228 	if (query_cap) {
229 		ret = ioctl(fd_update, PFRU_IOC_QUERY_CAP, &cap);
230 		if (ret)
231 			perror("Query Update Capability info failed.");
232 		else
233 			print_cap(&cap);
234 
235 		close(fd_update);
236 		close(fd_update_log);
237 
238 		return ret;
239 	}
240 
241 	if (log_getinfo) {
242 		ret = ioctl(fd_update_log, PFRT_LOG_IOC_GET_DATA_INFO, &data_info);
243 		if (ret) {
244 			perror("Get telemetry data info failed.");
245 			close(fd_update);
246 			close(fd_update_log);
247 
248 			return 1;
249 		}
250 
251 		ret = ioctl(fd_update_log, PFRT_LOG_IOC_GET_INFO, &info);
252 		if (ret) {
253 			perror("Get telemetry info failed.");
254 			close(fd_update);
255 			close(fd_update_log);
256 
257 			return 1;
258 		}
259 
260 		printf("log_level:%d\n", info.log_level);
261 		printf("log_type:%d\n", info.log_type);
262 		printf("log_revid:%d\n", info.log_revid);
263 		printf("max_data_size:%d\n", data_info.max_data_size);
264 		printf("chunk1_size:%d\n", data_info.chunk1_size);
265 		printf("chunk2_size:%d\n", data_info.chunk2_size);
266 		printf("rollover_cnt:%d\n", data_info.rollover_cnt);
267 		printf("reset_cnt:%d\n", data_info.reset_cnt);
268 
269 		return 0;
270 	}
271 
272 	info.log_level = -1;
273 	info.log_type = -1;
274 	info.log_revid = -1;
275 
276 	if (set_log_level) {
277 		if (!valid_log_level(log_level)) {
278 			printf("Invalid log level %d\n",
279 			       log_level);
280 		} else {
281 			info.log_level = log_level;
282 		}
283 	}
284 
285 	if (set_log_type) {
286 		if (!valid_log_type(log_type)) {
287 			printf("Invalid log type %d\n",
288 			       log_type);
289 		} else {
290 			info.log_type = log_type;
291 		}
292 	}
293 
294 	if (set_log_revid) {
295 		if (!valid_log_revid(log_revid)) {
296 			printf("Invalid log revid %d, unchanged.\n",
297 			       log_revid);
298 		} else {
299 			info.log_revid = log_revid;
300 		}
301 	}
302 
303 	ret = ioctl(fd_update_log, PFRT_LOG_IOC_SET_INFO, &info);
304 	if (ret) {
305 		perror("Log information set failed.(log_level, log_type, log_revid)");
306 		close(fd_update);
307 		close(fd_update_log);
308 
309 		return 1;
310 	}
311 
312 	if (set_revid) {
313 		ret = ioctl(fd_update, PFRU_IOC_SET_REV, &revid);
314 		if (ret) {
315 			perror("pfru update revid set failed");
316 			close(fd_update);
317 			close(fd_update_log);
318 
319 			return 1;
320 		}
321 
322 		printf("pfru update revid set to %d\n", revid);
323 	}
324 
325 	if (capsule_name) {
326 		fd_capsule = open(capsule_name, O_RDONLY);
327 		if (fd_capsule < 0) {
328 			perror("Can not open capsule file...");
329 			close(fd_update);
330 			close(fd_update_log);
331 
332 			return 1;
333 		}
334 
335 		if (fstat(fd_capsule, &st) < 0) {
336 			perror("Can not fstat capsule file...");
337 			close(fd_capsule);
338 			close(fd_update);
339 			close(fd_update_log);
340 
341 			return 1;
342 		}
343 
344 		addr_map_capsule = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED,
345 					fd_capsule, 0);
346 		if (addr_map_capsule == MAP_FAILED) {
347 			perror("Failed to mmap capsule file.");
348 			close(fd_capsule);
349 			close(fd_update);
350 			close(fd_update_log);
351 
352 			return 1;
353 		}
354 
355 		ret = write(fd_update, (char *)addr_map_capsule, st.st_size);
356 		printf("Load %d bytes of capsule file into the system\n",
357 		       ret);
358 
359 		if (ret == -1) {
360 			perror("Failed to load capsule file");
361 			close(fd_capsule);
362 			close(fd_update);
363 			close(fd_update_log);
364 
365 			return 1;
366 		}
367 
368 		munmap(addr_map_capsule, st.st_size);
369 		close(fd_capsule);
370 		printf("Load done.\n");
371 	}
372 
373 	if (action) {
374 		if (action == 1) {
375 			ret = ioctl(fd_update, PFRU_IOC_STAGE, NULL);
376 		} else if (action == 2) {
377 			ret = ioctl(fd_update, PFRU_IOC_ACTIVATE, NULL);
378 		} else if (action == 3) {
379 			ret = ioctl(fd_update, PFRU_IOC_STAGE_ACTIVATE, NULL);
380 		} else {
381 			close(fd_update);
382 			close(fd_update_log);
383 
384 			return 1;
385 		}
386 		printf("Update finished, return %d\n", ret);
387 	}
388 
389 	close(fd_update);
390 
391 	if (log_read) {
392 		void *p_mmap;
393 		int max_data_sz;
394 
395 		ret = ioctl(fd_update_log, PFRT_LOG_IOC_GET_DATA_INFO, &data_info);
396 		if (ret) {
397 			perror("Get telemetry data info failed.");
398 			close(fd_update_log);
399 
400 			return 1;
401 		}
402 
403 		max_data_sz = data_info.max_data_size;
404 		if (!max_data_sz) {
405 			printf("No telemetry data available.\n");
406 			close(fd_update_log);
407 
408 			return 1;
409 		}
410 
411 		log_buf = malloc(max_data_sz + 1);
412 		if (!log_buf) {
413 			perror("log_buf allocate failed.");
414 			close(fd_update_log);
415 
416 			return 1;
417 		}
418 
419 		p_mmap = mmap(NULL, max_data_sz, PROT_READ, MAP_SHARED, fd_update_log, 0);
420 		if (p_mmap == MAP_FAILED) {
421 			perror("mmap error.");
422 			close(fd_update_log);
423 
424 			return 1;
425 		}
426 
427 		memcpy(log_buf, p_mmap, max_data_sz);
428 		log_buf[max_data_sz] = '\0';
429 		printf("%s\n", log_buf);
430 		free(log_buf);
431 
432 		munmap(p_mmap, max_data_sz);
433 	}
434 
435 	close(fd_update_log);
436 
437 	return 0;
438 }
439