1 /* 2 * Implementation of get_cpuid(). 3 * 4 * Copyright IBM Corp. 2014, 2018 5 * Author(s): Alexander Yarygin <yarygin@linux.vnet.ibm.com> 6 * Thomas Richter <tmricht@linux.vnet.ibm.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License (version 2 only) 10 * as published by the Free Software Foundation. 11 */ 12 13 #include <sys/types.h> 14 #include <unistd.h> 15 #include <stdio.h> 16 #include <string.h> 17 #include <ctype.h> 18 19 #include "../../util/header.h" 20 #include "../../util/util.h" 21 22 #define SYSINFO_MANU "Manufacturer:" 23 #define SYSINFO_TYPE "Type:" 24 #define SYSINFO_MODEL "Model:" 25 #define SRVLVL_CPUMF "CPU-MF:" 26 #define SRVLVL_VERSION "version=" 27 #define SRVLVL_AUTHORIZATION "authorization=" 28 #define SYSINFO "/proc/sysinfo" 29 #define SRVLVL "/proc/service_levels" 30 31 int get_cpuid(char *buffer, size_t sz) 32 { 33 char *cp, *line = NULL, *line2; 34 char type[8], model[33], version[8], manufacturer[32], authorization[8]; 35 int tpsize = 0, mdsize = 0, vssize = 0, mfsize = 0, atsize = 0; 36 int read; 37 unsigned long line_sz; 38 size_t nbytes; 39 FILE *sysinfo; 40 41 /* 42 * Scan /proc/sysinfo line by line and read out values for 43 * Manufacturer:, Type: and Model:, for example: 44 * Manufacturer: IBM 45 * Type: 2964 46 * Model: 702 N96 47 * The first word is the Model Capacity and the second word is 48 * Model (can be omitted). Both words have a maximum size of 16 49 * bytes. 50 */ 51 memset(manufacturer, 0, sizeof(manufacturer)); 52 memset(type, 0, sizeof(type)); 53 memset(model, 0, sizeof(model)); 54 memset(version, 0, sizeof(version)); 55 memset(authorization, 0, sizeof(authorization)); 56 57 sysinfo = fopen(SYSINFO, "r"); 58 if (sysinfo == NULL) 59 return -1; 60 61 while ((read = getline(&line, &line_sz, sysinfo)) != -1) { 62 if (!strncmp(line, SYSINFO_MANU, strlen(SYSINFO_MANU))) { 63 line2 = line + strlen(SYSINFO_MANU); 64 65 while ((cp = strtok_r(line2, "\n ", &line2))) { 66 mfsize += scnprintf(manufacturer + mfsize, 67 sizeof(manufacturer) - mfsize, "%s", cp); 68 } 69 } 70 71 if (!strncmp(line, SYSINFO_TYPE, strlen(SYSINFO_TYPE))) { 72 line2 = line + strlen(SYSINFO_TYPE); 73 74 while ((cp = strtok_r(line2, "\n ", &line2))) { 75 tpsize += scnprintf(type + tpsize, 76 sizeof(type) - tpsize, "%s", cp); 77 } 78 } 79 80 if (!strncmp(line, SYSINFO_MODEL, strlen(SYSINFO_MODEL))) { 81 line2 = line + strlen(SYSINFO_MODEL); 82 83 while ((cp = strtok_r(line2, "\n ", &line2))) { 84 mdsize += scnprintf(model + mdsize, sizeof(model) - mdsize, 85 "%s%s", model[0] ? "," : "", cp); 86 } 87 break; 88 } 89 } 90 fclose(sysinfo); 91 92 /* Missing manufacturer, type or model information should not happen */ 93 if (!manufacturer[0] || !type[0] || !model[0]) 94 return -1; 95 96 /* 97 * Scan /proc/service_levels and return the CPU-MF counter facility 98 * version number and authorization level. 99 * Optional, does not exist on z/VM guests. 100 */ 101 sysinfo = fopen(SRVLVL, "r"); 102 if (sysinfo == NULL) 103 goto skip_sysinfo; 104 while ((read = getline(&line, &line_sz, sysinfo)) != -1) { 105 if (strncmp(line, SRVLVL_CPUMF, strlen(SRVLVL_CPUMF))) 106 continue; 107 108 line2 = line + strlen(SRVLVL_CPUMF); 109 while ((cp = strtok_r(line2, "\n ", &line2))) { 110 if (!strncmp(cp, SRVLVL_VERSION, 111 strlen(SRVLVL_VERSION))) { 112 char *sep = strchr(cp, '='); 113 114 vssize += scnprintf(version + vssize, 115 sizeof(version) - vssize, "%s", sep + 1); 116 } 117 if (!strncmp(cp, SRVLVL_AUTHORIZATION, 118 strlen(SRVLVL_AUTHORIZATION))) { 119 char *sep = strchr(cp, '='); 120 121 atsize += scnprintf(authorization + atsize, 122 sizeof(authorization) - atsize, "%s", sep + 1); 123 } 124 } 125 } 126 fclose(sysinfo); 127 128 skip_sysinfo: 129 free(line); 130 131 if (version[0] && authorization[0] ) 132 nbytes = snprintf(buffer, sz, "%s,%s,%s,%s,%s", 133 manufacturer, type, model, version, 134 authorization); 135 else 136 nbytes = snprintf(buffer, sz, "%s,%s,%s", manufacturer, type, 137 model); 138 return (nbytes >= sz) ? -1 : 0; 139 } 140 141 char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused) 142 { 143 char *buf = malloc(128); 144 145 if (buf && get_cpuid(buf, 128) < 0) 146 zfree(&buf); 147 return buf; 148 } 149