forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
3.9 KiB
147 lines
3.9 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* |
|
* Implementation of get_cpuid(). |
|
* |
|
* Copyright IBM Corp. 2014, 2018 |
|
* Author(s): Alexander Yarygin <[email protected]> |
|
* Thomas Richter <[email protected]> |
|
*/ |
|
|
|
#include <sys/types.h> |
|
#include <errno.h> |
|
#include <unistd.h> |
|
#include <stdio.h> |
|
#include <string.h> |
|
#include <linux/ctype.h> |
|
#include <linux/kernel.h> |
|
#include <linux/zalloc.h> |
|
|
|
#include "../../util/header.h" |
|
|
|
#define SYSINFO_MANU "Manufacturer:" |
|
#define SYSINFO_TYPE "Type:" |
|
#define SYSINFO_MODEL "Model:" |
|
#define SRVLVL_CPUMF "CPU-MF:" |
|
#define SRVLVL_VERSION "version=" |
|
#define SRVLVL_AUTHORIZATION "authorization=" |
|
#define SYSINFO "/proc/sysinfo" |
|
#define SRVLVL "/proc/service_levels" |
|
|
|
int get_cpuid(char *buffer, size_t sz) |
|
{ |
|
char *cp, *line = NULL, *line2; |
|
char type[8], model[33], version[8], manufacturer[32], authorization[8]; |
|
int tpsize = 0, mdsize = 0, vssize = 0, mfsize = 0, atsize = 0; |
|
int read; |
|
unsigned long line_sz; |
|
size_t nbytes; |
|
FILE *sysinfo; |
|
|
|
/* |
|
* Scan /proc/sysinfo line by line and read out values for |
|
* Manufacturer:, Type: and Model:, for example: |
|
* Manufacturer: IBM |
|
* Type: 2964 |
|
* Model: 702 N96 |
|
* The first word is the Model Capacity and the second word is |
|
* Model (can be omitted). Both words have a maximum size of 16 |
|
* bytes. |
|
*/ |
|
memset(manufacturer, 0, sizeof(manufacturer)); |
|
memset(type, 0, sizeof(type)); |
|
memset(model, 0, sizeof(model)); |
|
memset(version, 0, sizeof(version)); |
|
memset(authorization, 0, sizeof(authorization)); |
|
|
|
sysinfo = fopen(SYSINFO, "r"); |
|
if (sysinfo == NULL) |
|
return errno; |
|
|
|
while ((read = getline(&line, &line_sz, sysinfo)) != -1) { |
|
if (!strncmp(line, SYSINFO_MANU, strlen(SYSINFO_MANU))) { |
|
line2 = line + strlen(SYSINFO_MANU); |
|
|
|
while ((cp = strtok_r(line2, "\n ", &line2))) { |
|
mfsize += scnprintf(manufacturer + mfsize, |
|
sizeof(manufacturer) - mfsize, "%s", cp); |
|
} |
|
} |
|
|
|
if (!strncmp(line, SYSINFO_TYPE, strlen(SYSINFO_TYPE))) { |
|
line2 = line + strlen(SYSINFO_TYPE); |
|
|
|
while ((cp = strtok_r(line2, "\n ", &line2))) { |
|
tpsize += scnprintf(type + tpsize, |
|
sizeof(type) - tpsize, "%s", cp); |
|
} |
|
} |
|
|
|
if (!strncmp(line, SYSINFO_MODEL, strlen(SYSINFO_MODEL))) { |
|
line2 = line + strlen(SYSINFO_MODEL); |
|
|
|
while ((cp = strtok_r(line2, "\n ", &line2))) { |
|
mdsize += scnprintf(model + mdsize, sizeof(model) - mdsize, |
|
"%s%s", model[0] ? "," : "", cp); |
|
} |
|
break; |
|
} |
|
} |
|
fclose(sysinfo); |
|
|
|
/* Missing manufacturer, type or model information should not happen */ |
|
if (!manufacturer[0] || !type[0] || !model[0]) |
|
return EINVAL; |
|
|
|
/* |
|
* Scan /proc/service_levels and return the CPU-MF counter facility |
|
* version number and authorization level. |
|
* Optional, does not exist on z/VM guests. |
|
*/ |
|
sysinfo = fopen(SRVLVL, "r"); |
|
if (sysinfo == NULL) |
|
goto skip_sysinfo; |
|
while ((read = getline(&line, &line_sz, sysinfo)) != -1) { |
|
if (strncmp(line, SRVLVL_CPUMF, strlen(SRVLVL_CPUMF))) |
|
continue; |
|
|
|
line2 = line + strlen(SRVLVL_CPUMF); |
|
while ((cp = strtok_r(line2, "\n ", &line2))) { |
|
if (!strncmp(cp, SRVLVL_VERSION, |
|
strlen(SRVLVL_VERSION))) { |
|
char *sep = strchr(cp, '='); |
|
|
|
vssize += scnprintf(version + vssize, |
|
sizeof(version) - vssize, "%s", sep + 1); |
|
} |
|
if (!strncmp(cp, SRVLVL_AUTHORIZATION, |
|
strlen(SRVLVL_AUTHORIZATION))) { |
|
char *sep = strchr(cp, '='); |
|
|
|
atsize += scnprintf(authorization + atsize, |
|
sizeof(authorization) - atsize, "%s", sep + 1); |
|
} |
|
} |
|
} |
|
fclose(sysinfo); |
|
|
|
skip_sysinfo: |
|
free(line); |
|
|
|
if (version[0] && authorization[0] ) |
|
nbytes = snprintf(buffer, sz, "%s,%s,%s,%s,%s", |
|
manufacturer, type, model, version, |
|
authorization); |
|
else |
|
nbytes = snprintf(buffer, sz, "%s,%s,%s", manufacturer, type, |
|
model); |
|
return (nbytes >= sz) ? ENOBUFS : 0; |
|
} |
|
|
|
char *get_cpuid_str(struct perf_pmu *pmu __maybe_unused) |
|
{ |
|
char *buf = malloc(128); |
|
|
|
if (buf && get_cpuid(buf, 128)) |
|
zfree(&buf); |
|
return buf; |
|
}
|
|
|