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