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 27char *capsule_name; 28int action, query_cap, log_type, log_level, log_read, log_getinfo, 29 revid, log_revid; 30int set_log_level, set_log_type, 31 set_revid, set_log_revid; 32 33char *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 44static int valid_log_level(int level) 45{ 46 return level == LOG_ERR || level == LOG_WARN || 47 level == LOG_INFO || level == LOG_VERB; 48} 49 50static int valid_log_type(int type) 51{ 52 return type == LOG_EXEC_IDX || type == LOG_HISTORY_IDX; 53} 54 55static inline int valid_log_revid(int id) 56{ 57 return id == REVID_1 || id == REVID_2; 58} 59 60static 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 80char *option_string = "l:sauqd:GT:L:RD:h"; 81static 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 97static 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 167void 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 196int 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} 437