Linux 6.7-rc7
[linux-modified.git] / tools / power / acpi / tools / pfrut / pfrut.c
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
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
50 static int valid_log_type(int type)
51 {
52         return type == LOG_EXEC_IDX || type == LOG_HISTORY_IDX;
53 }
54
55 static inline int valid_log_revid(int id)
56 {
57         return id == REVID_1 || id == REVID_2;
58 }
59
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
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
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         uuid_unparse(cap->code_type, uuid);
178         printf("code injection image type:%s\n", uuid);
179         printf("fw_version:%d\n", cap->fw_version);
180         printf("code_rt_version:%d\n", cap->code_rt_version);
181
182         uuid_unparse(cap->drv_type, uuid);
183         printf("driver update image type:%s\n", uuid);
184         printf("drv_rt_version:%d\n", cap->drv_rt_version);
185         printf("drv_svn:%d\n", cap->drv_svn);
186
187         uuid_unparse(cap->platform_id, uuid);
188         printf("platform id:%s\n", uuid);
189         uuid_unparse(cap->oem_id, uuid);
190         printf("oem id:%s\n", uuid);
191         printf("oem information length:%d\n", cap->oem_info_len);
192
193         free(uuid);
194 }
195
196 int main(int argc, char *argv[])
197 {
198         int fd_update, fd_update_log, fd_capsule;
199         struct pfrt_log_data_info data_info;
200         struct pfrt_log_info info;
201         struct pfru_update_cap_info cap;
202         void *addr_map_capsule;
203         struct stat st;
204         char *log_buf;
205         int ret;
206
207         if (getuid() != 0) {
208                 printf("Please run the tool as root - Exiting.\n");
209                 return 1;
210         }
211
212         parse_options(argc, argv);
213
214         fd_update = open("/dev/acpi_pfr_update0", O_RDWR);
215         if (fd_update < 0) {
216                 printf("PFRU device not supported - Quit...\n");
217                 return 1;
218         }
219
220         fd_update_log = open("/dev/acpi_pfr_telemetry0", O_RDWR);
221         if (fd_update_log < 0) {
222                 printf("PFRT device not supported - Quit...\n");
223                 return 1;
224         }
225
226         if (query_cap) {
227                 ret = ioctl(fd_update, PFRU_IOC_QUERY_CAP, &cap);
228                 if (ret)
229                         perror("Query Update Capability info failed.");
230                 else
231                         print_cap(&cap);
232
233                 close(fd_update);
234                 close(fd_update_log);
235
236                 return ret;
237         }
238
239         if (log_getinfo) {
240                 ret = ioctl(fd_update_log, PFRT_LOG_IOC_GET_DATA_INFO, &data_info);
241                 if (ret) {
242                         perror("Get telemetry data info failed.");
243                         close(fd_update);
244                         close(fd_update_log);
245
246                         return 1;
247                 }
248
249                 ret = ioctl(fd_update_log, PFRT_LOG_IOC_GET_INFO, &info);
250                 if (ret) {
251                         perror("Get telemetry info failed.");
252                         close(fd_update);
253                         close(fd_update_log);
254
255                         return 1;
256                 }
257
258                 printf("log_level:%d\n", info.log_level);
259                 printf("log_type:%d\n", info.log_type);
260                 printf("log_revid:%d\n", info.log_revid);
261                 printf("max_data_size:%d\n", data_info.max_data_size);
262                 printf("chunk1_size:%d\n", data_info.chunk1_size);
263                 printf("chunk2_size:%d\n", data_info.chunk2_size);
264                 printf("rollover_cnt:%d\n", data_info.rollover_cnt);
265                 printf("reset_cnt:%d\n", data_info.reset_cnt);
266
267                 return 0;
268         }
269
270         info.log_level = -1;
271         info.log_type = -1;
272         info.log_revid = -1;
273
274         if (set_log_level) {
275                 if (!valid_log_level(log_level)) {
276                         printf("Invalid log level %d\n",
277                                log_level);
278                 } else {
279                         info.log_level = log_level;
280                 }
281         }
282
283         if (set_log_type) {
284                 if (!valid_log_type(log_type)) {
285                         printf("Invalid log type %d\n",
286                                log_type);
287                 } else {
288                         info.log_type = log_type;
289                 }
290         }
291
292         if (set_log_revid) {
293                 if (!valid_log_revid(log_revid)) {
294                         printf("Invalid log revid %d, unchanged.\n",
295                                log_revid);
296                 } else {
297                         info.log_revid = log_revid;
298                 }
299         }
300
301         ret = ioctl(fd_update_log, PFRT_LOG_IOC_SET_INFO, &info);
302         if (ret) {
303                 perror("Log information set failed.(log_level, log_type, log_revid)");
304                 close(fd_update);
305                 close(fd_update_log);
306
307                 return 1;
308         }
309
310         if (set_revid) {
311                 ret = ioctl(fd_update, PFRU_IOC_SET_REV, &revid);
312                 if (ret) {
313                         perror("pfru update revid set failed");
314                         close(fd_update);
315                         close(fd_update_log);
316
317                         return 1;
318                 }
319
320                 printf("pfru update revid set to %d\n", revid);
321         }
322
323         if (capsule_name) {
324                 fd_capsule = open(capsule_name, O_RDONLY);
325                 if (fd_capsule < 0) {
326                         perror("Can not open capsule file...");
327                         close(fd_update);
328                         close(fd_update_log);
329
330                         return 1;
331                 }
332
333                 if (fstat(fd_capsule, &st) < 0) {
334                         perror("Can not fstat capsule file...");
335                         close(fd_capsule);
336                         close(fd_update);
337                         close(fd_update_log);
338
339                         return 1;
340                 }
341
342                 addr_map_capsule = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED,
343                                         fd_capsule, 0);
344                 if (addr_map_capsule == MAP_FAILED) {
345                         perror("Failed to mmap capsule file.");
346                         close(fd_capsule);
347                         close(fd_update);
348                         close(fd_update_log);
349
350                         return 1;
351                 }
352
353                 ret = write(fd_update, (char *)addr_map_capsule, st.st_size);
354                 printf("Load %d bytes of capsule file into the system\n",
355                        ret);
356
357                 if (ret == -1) {
358                         perror("Failed to load capsule file");
359                         close(fd_capsule);
360                         close(fd_update);
361                         close(fd_update_log);
362
363                         return 1;
364                 }
365
366                 munmap(addr_map_capsule, st.st_size);
367                 close(fd_capsule);
368                 printf("Load done.\n");
369         }
370
371         if (action) {
372                 if (action == 1) {
373                         ret = ioctl(fd_update, PFRU_IOC_STAGE, NULL);
374                 } else if (action == 2) {
375                         ret = ioctl(fd_update, PFRU_IOC_ACTIVATE, NULL);
376                 } else if (action == 3) {
377                         ret = ioctl(fd_update, PFRU_IOC_STAGE_ACTIVATE, NULL);
378                 } else {
379                         close(fd_update);
380                         close(fd_update_log);
381
382                         return 1;
383                 }
384                 printf("Update finished, return %d\n", ret);
385         }
386
387         close(fd_update);
388
389         if (log_read) {
390                 void *p_mmap;
391                 int max_data_sz;
392
393                 ret = ioctl(fd_update_log, PFRT_LOG_IOC_GET_DATA_INFO, &data_info);
394                 if (ret) {
395                         perror("Get telemetry data info failed.");
396                         close(fd_update_log);
397
398                         return 1;
399                 }
400
401                 max_data_sz = data_info.max_data_size;
402                 if (!max_data_sz) {
403                         printf("No telemetry data available.\n");
404                         close(fd_update_log);
405
406                         return 1;
407                 }
408
409                 log_buf = malloc(max_data_sz + 1);
410                 if (!log_buf) {
411                         perror("log_buf allocate failed.");
412                         close(fd_update_log);
413
414                         return 1;
415                 }
416
417                 p_mmap = mmap(NULL, max_data_sz, PROT_READ, MAP_SHARED, fd_update_log, 0);
418                 if (p_mmap == MAP_FAILED) {
419                         perror("mmap error.");
420                         close(fd_update_log);
421
422                         return 1;
423                 }
424
425                 memcpy(log_buf, p_mmap, max_data_sz);
426                 log_buf[max_data_sz] = '\0';
427                 printf("%s\n", log_buf);
428                 free(log_buf);
429
430                 munmap(p_mmap, max_data_sz);
431         }
432
433         close(fd_update_log);
434
435         return 0;
436 }