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 close(fd_update);
226 return 1;
227 }
228
229 if (query_cap) {
230 ret = ioctl(fd_update, PFRU_IOC_QUERY_CAP, &cap);
231 if (ret)
232 perror("Query Update Capability info failed.");
233 else
234 print_cap(&cap);
235
236 close(fd_update);
237 close(fd_update_log);
238
239 return ret;
240 }
241
242 if (log_getinfo) {
243 ret = ioctl(fd_update_log, PFRT_LOG_IOC_GET_DATA_INFO, &data_info);
244 if (ret) {
245 perror("Get telemetry data info failed.");
246 close(fd_update);
247 close(fd_update_log);
248
249 return 1;
250 }
251
252 ret = ioctl(fd_update_log, PFRT_LOG_IOC_GET_INFO, &info);
253 if (ret) {
254 perror("Get telemetry info failed.");
255 close(fd_update);
256 close(fd_update_log);
257
258 return 1;
259 }
260
261 printf("log_level:%d\n", info.log_level);
262 printf("log_type:%d\n", info.log_type);
263 printf("log_revid:%d\n", info.log_revid);
264 printf("max_data_size:%d\n", data_info.max_data_size);
265 printf("chunk1_size:%d\n", data_info.chunk1_size);
266 printf("chunk2_size:%d\n", data_info.chunk2_size);
267 printf("rollover_cnt:%d\n", data_info.rollover_cnt);
268 printf("reset_cnt:%d\n", data_info.reset_cnt);
269 close(fd_update);
270 close(fd_update_log);
271 return 0;
272 }
273
274 info.log_level = -1;
275 info.log_type = -1;
276 info.log_revid = -1;
277
278 if (set_log_level) {
279 if (!valid_log_level(log_level)) {
280 printf("Invalid log level %d\n",
281 log_level);
282 } else {
283 info.log_level = log_level;
284 }
285 }
286
287 if (set_log_type) {
288 if (!valid_log_type(log_type)) {
289 printf("Invalid log type %d\n",
290 log_type);
291 } else {
292 info.log_type = log_type;
293 }
294 }
295
296 if (set_log_revid) {
297 if (!valid_log_revid(log_revid)) {
298 printf("Invalid log revid %d, unchanged.\n",
299 log_revid);
300 } else {
301 info.log_revid = log_revid;
302 }
303 }
304
305 ret = ioctl(fd_update_log, PFRT_LOG_IOC_SET_INFO, &info);
306 if (ret) {
307 perror("Log information set failed.(log_level, log_type, log_revid)");
308 close(fd_update);
309 close(fd_update_log);
310
311 return 1;
312 }
313
314 if (set_revid) {
315 ret = ioctl(fd_update, PFRU_IOC_SET_REV, &revid);
316 if (ret) {
317 perror("pfru update revid set failed");
318 close(fd_update);
319 close(fd_update_log);
320
321 return 1;
322 }
323
324 printf("pfru update revid set to %d\n", revid);
325 }
326
327 if (capsule_name) {
328 fd_capsule = open(capsule_name, O_RDONLY);
329 if (fd_capsule < 0) {
330 perror("Can not open capsule file...");
331 close(fd_update);
332 close(fd_update_log);
333
334 return 1;
335 }
336
337 if (fstat(fd_capsule, &st) < 0) {
338 perror("Can not fstat capsule file...");
339 close(fd_capsule);
340 close(fd_update);
341 close(fd_update_log);
342
343 return 1;
344 }
345
346 addr_map_capsule = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED,
347 fd_capsule, 0);
348 if (addr_map_capsule == MAP_FAILED) {
349 perror("Failed to mmap capsule file.");
350 close(fd_capsule);
351 close(fd_update);
352 close(fd_update_log);
353
354 return 1;
355 }
356
357 ret = write(fd_update, (char *)addr_map_capsule, st.st_size);
358 printf("Load %d bytes of capsule file into the system\n",
359 ret);
360
361 if (ret == -1) {
362 perror("Failed to load capsule file");
363 munmap(addr_map_capsule, st.st_size);
364 close(fd_capsule);
365 close(fd_update);
366 close(fd_update_log);
367
368 return 1;
369 }
370
371 munmap(addr_map_capsule, st.st_size);
372 close(fd_capsule);
373 printf("Load done.\n");
374 }
375
376 if (action) {
377 if (action == 1) {
378 ret = ioctl(fd_update, PFRU_IOC_STAGE, NULL);
379 } else if (action == 2) {
380 ret = ioctl(fd_update, PFRU_IOC_ACTIVATE, NULL);
381 } else if (action == 3) {
382 ret = ioctl(fd_update, PFRU_IOC_STAGE_ACTIVATE, NULL);
383 } else {
384 close(fd_update);
385 close(fd_update_log);
386
387 return 1;
388 }
389 printf("Update finished, return %d\n", ret);
390 }
391
392 close(fd_update);
393
394 if (log_read) {
395 void *p_mmap;
396 int max_data_sz;
397
398 ret = ioctl(fd_update_log, PFRT_LOG_IOC_GET_DATA_INFO, &data_info);
399 if (ret) {
400 perror("Get telemetry data info failed.");
401 close(fd_update_log);
402
403 return 1;
404 }
405
406 max_data_sz = data_info.max_data_size;
407 if (!max_data_sz) {
408 printf("No telemetry data available.\n");
409 close(fd_update_log);
410
411 return 1;
412 }
413
414 log_buf = malloc(max_data_sz + 1);
415 if (!log_buf) {
416 perror("log_buf allocate failed.");
417 close(fd_update_log);
418
419 return 1;
420 }
421
422 p_mmap = mmap(NULL, max_data_sz, PROT_READ, MAP_SHARED, fd_update_log, 0);
423 if (p_mmap == MAP_FAILED) {
424 perror("mmap error.");
425 close(fd_update_log);
426 free(log_buf);
427 return 1;
428 }
429
430 memcpy(log_buf, p_mmap, max_data_sz);
431 log_buf[max_data_sz] = '\0';
432 printf("%s\n", log_buf);
433 free(log_buf);
434
435 munmap(p_mmap, max_data_sz);
436 }
437
438 close(fd_update_log);
439
440 return 0;
441 }
442