From aa1cb7501fead18583f08c616f38f4a1e89f0e5f Mon Sep 17 00:00:00 2001 From: Attilio Rao Date: Thu, 19 Jun 2014 21:54:41 +0000 Subject: [PATCH] Following comments in r242565 add the possibility to specify ecx when performing cpuid calls. Add also a new way to specify the level type to cpucontrol(8) as reported in the manpage. Sponsored by: EMC / Isilon storage division Reviewed by: bdrewery, gcooper Testerd by: bdrewery --- share/man/man4/cpuctl.4 | 12 +++++-- sys/dev/cpuctl/cpuctl.c | 23 ++++++++++--- sys/sys/cpuctl.h | 4 ++- usr.sbin/cpucontrol/cpucontrol.8 | 9 +++++ usr.sbin/cpucontrol/cpucontrol.c | 59 ++++++++++++++++++++++++++++++-- 5 files changed, 98 insertions(+), 9 deletions(-) diff --git a/share/man/man4/cpuctl.4 b/share/man/man4/cpuctl.4 index ed80f8aae1cd..3aff1e3c11d5 100644 --- a/share/man/man4/cpuctl.4 +++ b/share/man/man4/cpuctl.4 @@ -86,19 +86,27 @@ Set/clear MSR bits according to the mask given in the .Va data field. .It Dv CPUCTL_CPUID Fa cpuctl_cpuid_args_t *args +.It Dv CPUCTL_CPUID_COUNT Fa cpuctl_cpuid_args_t *args Retrieve CPUID information. Arguments are supplied in the following struct: .Bd -literal typedef struct { - int level; /* CPUID level */ + int level; /* CPUID level */ + int level_type; /* CPUID level type */ uint32_t data[4]; } cpuctl_cpuid_args_t; .Ed .Pp The .Va level -field indicates the CPUID level to retrieve information for, while the +field indicates the CPUID level to retrieve. +The +.Va level_type +field indicates the CPUID level type to retrieve. +It is overriden to 0 for +.Va CPUCTL_CPUID . +Finally, the .Va data field is used to store the received CPUID data. .It Dv CPUCTL_UPDATE cpuctl_update_args_t *args diff --git a/sys/dev/cpuctl/cpuctl.c b/sys/dev/cpuctl/cpuctl.c index 236d687c4180..63187bdc4b8b 100644 --- a/sys/dev/cpuctl/cpuctl.c +++ b/sys/dev/cpuctl/cpuctl.c @@ -69,6 +69,8 @@ static int cpuctl_do_msr(int cpu, cpuctl_msr_args_t *data, u_long cmd, struct thread *td); static int cpuctl_do_cpuid(int cpu, cpuctl_cpuid_args_t *data, struct thread *td); +static int cpuctl_do_cpuid_count(int cpu, cpuctl_cpuid_args_t *data, + struct thread *td); static int cpuctl_do_update(int cpu, cpuctl_update_args_t *data, struct thread *td); static int update_intel(int cpu, cpuctl_update_args_t *args, @@ -177,6 +179,10 @@ cpuctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, goto fail; ret = cpuctl_do_update(cpu, (cpuctl_update_args_t *)data, td); break; + case CPUCTL_CPUID_COUNT: + ret = cpuctl_do_cpuid_count(cpu, (cpuctl_cpuid_args_t *)data, + td); + break; default: ret = EINVAL; break; @@ -189,7 +195,7 @@ cpuctl_ioctl(struct cdev *dev, u_long cmd, caddr_t data, * Actually perform cpuid operation. */ static int -cpuctl_do_cpuid(int cpu, cpuctl_cpuid_args_t *data, struct thread *td) +cpuctl_do_cpuid_count(int cpu, cpuctl_cpuid_args_t *data, struct thread *td) { int is_bound = 0; int oldcpu; @@ -199,16 +205,25 @@ cpuctl_do_cpuid(int cpu, cpuctl_cpuid_args_t *data, struct thread *td) /* Explicitly clear cpuid data to avoid returning stale info. */ bzero(data->data, sizeof(data->data)); - DPRINTF("[cpuctl,%d]: retriving cpuid level %#0x for %d cpu\n", - __LINE__, data->level, cpu); + DPRINTF("[cpuctl,%d]: retrieving cpuid lev %#0x type %#0x for %d cpu\n", + __LINE__, data->level, data->level_type, cpu); oldcpu = td->td_oncpu; is_bound = cpu_sched_is_bound(td); set_cpu(cpu, td); - cpuid_count(data->level, 0, data->data); + cpuid_count(data->level, data->level_type, data->data); restore_cpu(oldcpu, is_bound, td); return (0); } +static int +cpuctl_do_cpuid(int cpu, cpuctl_cpuid_args_t *data, struct thread *td) +{ + + /* Override the level type. */ + data->level_type = 0; + return (cpuctl_do_cpuid_count(cpu, data, td)); +} + /* * Actually perform MSR operations. */ diff --git a/sys/sys/cpuctl.h b/sys/sys/cpuctl.h index 4bddb345611c..4220dee33186 100644 --- a/sys/sys/cpuctl.h +++ b/sys/sys/cpuctl.h @@ -35,7 +35,8 @@ typedef struct { } cpuctl_msr_args_t; typedef struct { - int level; /* CPUID level */ + int level; /* CPUID level */ + int level_type; /* CPUID level type */ uint32_t data[4]; } cpuctl_cpuid_args_t; @@ -50,5 +51,6 @@ typedef struct { #define CPUCTL_UPDATE _IOWR('c', 4, cpuctl_update_args_t) #define CPUCTL_MSRSBIT _IOWR('c', 5, cpuctl_msr_args_t) #define CPUCTL_MSRCBIT _IOWR('c', 6, cpuctl_msr_args_t) +#define CPUCTL_CPUID_COUNT _IOWR('c', 7, cpuctl_cpuid_args_t) #endif /* _CPUCTL_H_ */ diff --git a/usr.sbin/cpucontrol/cpucontrol.8 b/usr.sbin/cpucontrol/cpucontrol.8 index 0998b2056593..cb1a29e927a4 100644 --- a/usr.sbin/cpucontrol/cpucontrol.8 +++ b/usr.sbin/cpucontrol/cpucontrol.8 @@ -65,6 +65,12 @@ device .Ek .Nm .Op Fl vh +.Fl i Ar level,level_type +.Bk +.Ar device +.Ek +.Nm +.Op Fl vh .Op Fl d Ar datadir .Fl u .Bk @@ -114,6 +120,9 @@ In this case the inverted value of mask will be used. .It Fl i Ar level Retrieve CPUID info. Level should be given as a hex number. +.It Fl i Ar level,level_type +Retrieve CPUID info. +Level and level_type should be given as hex numbers. .It Fl u Apply CPU firmware updates. The diff --git a/usr.sbin/cpucontrol/cpucontrol.c b/usr.sbin/cpucontrol/cpucontrol.c index c0d5a3132d8d..9832d9fd0706 100644 --- a/usr.sbin/cpucontrol/cpucontrol.c +++ b/usr.sbin/cpucontrol/cpucontrol.c @@ -99,6 +99,7 @@ static struct ucode_handler { static void usage(void); static int isdir(const char *path); static int do_cpuid(const char *cmdarg, const char *dev); +static int do_cpuid_count(const char *cmdarg, const char *dev); static int do_msr(const char *cmdarg, const char *dev); static int do_update(const char *dev); static void datadir_add(const char *path); @@ -112,7 +113,7 @@ usage(void) if (name == NULL) name = "cpuctl"; fprintf(stderr, "Usage: %s [-vh] [-d datadir] [-m msr[=value] | " - "-i level | -u] device\n", name); + "-i level | -i level,level_type | -u] device\n", name); exit(EX_USAGE); } @@ -169,6 +170,57 @@ do_cpuid(const char *cmdarg, const char *dev) return (0); } +static int +do_cpuid_count(const char *cmdarg, const char *dev) +{ + char *cmdarg1, *endptr, *endptr1; + unsigned int level, level_type; + cpuctl_cpuid_args_t args; + int fd, error; + + assert(cmdarg != NULL); + assert(dev != NULL); + + level = strtoul(cmdarg, &endptr, 16); + if (*cmdarg == '\0' || *endptr == '\0') { + WARNX(0, "incorrect or missing operand: %s", cmdarg); + usage(); + /* NOTREACHED */ + } + /* Locate the comma... */ + cmdarg1 = strstr(endptr, ","); + /* ... and skip past it */ + cmdarg1 += 1; + level_type = strtoul(cmdarg1, &endptr1, 16); + if (*cmdarg1 == '\0' || *endptr1 != '\0') { + WARNX(0, "incorrect or missing operand: %s", cmdarg); + usage(); + /* NOTREACHED */ + } + + /* + * Fill ioctl argument structure. + */ + args.level = level; + args.level_type = level_type; + fd = open(dev, O_RDONLY); + if (fd < 0) { + WARN(0, "error opening %s for reading", dev); + return (1); + } + error = ioctl(fd, CPUCTL_CPUID_COUNT, &args); + if (error < 0) { + WARN(0, "ioctl(%s, CPUCTL_CPUID_COUNT)", dev); + close(fd); + return (error); + } + fprintf(stdout, "cpuid level 0x%x, level_type 0x%x: 0x%.8x 0x%.8x " + "0x%.8x 0x%.8x\n", level, level_type, args.data[0], args.data[1], + args.data[2], args.data[3]); + close(fd); + return (0); +} + static int do_msr(const char *cmdarg, const char *dev) { @@ -414,7 +466,10 @@ main(int argc, char *argv[]) c = flags & (FLAG_I | FLAG_M | FLAG_U); switch (c) { case FLAG_I: - error = do_cpuid(cmdarg, dev); + if (strstr(cmdarg, ",") != NULL) + error = do_cpuid_count(cmdarg, dev); + else + error = do_cpuid(cmdarg, dev); break; case FLAG_M: error = do_msr(cmdarg, dev);