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